diff --git a/app/controllers/agile_boards_controller.rb b/app/controllers/agile_boards_controller.rb
index 8d940b2..1f6b824 100755
--- a/app/controllers/agile_boards_controller.rb
+++ b/app/controllers/agile_boards_controller.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
@@ -51,7 +51,7 @@ class AgileBoardsController < ApplicationController
include SortHelper
include IssuesHelper
helper :timelog
- include RedmineAgile::AgileHelper
+ include RedmineAgile::Helpers::AgileHelper
helper :checklists if RedmineAgile.use_checklist?
def index
@@ -81,10 +81,10 @@ class AgileBoardsController < ApplicationController
retrieve_agile_query_from_session
old_status = @issue.status
@issue.init_journal(User.current)
- @issue.safe_attributes = auto_assign_on_move? ? params[:issue].merge(:assigned_to_id => User.current.id) : params[:issue]
- checking_params = params.respond_to?(:to_unsafe_hash) ? params.to_unsafe_hash : params
- saved = checking_params['issue'] && checking_params['issue'].inject(true) do |total, attribute|
+ @issue.safe_attributes = configured_params['issue']
+
+ saved = configured_params['issue'] && configured_params['issue'].inject(true) do |total, attribute|
if @issue.attributes.include?(attribute.first)
total &&= @issue.attributes[attribute.first].to_i == attribute.last.to_i
else
@@ -138,6 +138,16 @@ class AgileBoardsController < ApplicationController
private
+ def configured_params
+ return @configured_params if @configured_params
+
+ issue_params = params[:issue]
+ issue_params[:parent_issue_id] = issue_params[:parent_id] && issue_params.delete(:parent_id) if issue_params[:parent_id]
+ issue_params[:assigned_to_id] = User.current.id if auto_assign_on_move?
+
+ @configured_params = params.respond_to?(:to_unsafe_hash) ? params.to_unsafe_hash : params
+ end
+
def auto_assign_on_move?
RedmineAgile.auto_assign_on_move? && @issue.assigned_to.nil? &&
!params[:issue].keys.include?('assigned_to_id') &&
diff --git a/app/controllers/agile_charts_controller.rb b/app/controllers/agile_charts_controller.rb
index 5fd0ebe..101b76d 100644
--- a/app/controllers/agile_charts_controller.rb
+++ b/app/controllers/agile_charts_controller.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
@@ -45,7 +45,7 @@ class AgileChartsController < ApplicationController
include SortHelper
include IssuesHelper
helper :timelog
- include RedmineAgile::AgileHelper
+ include RedmineAgile::Helpers::AgileHelper
def show
retrieve_charts_query
@@ -85,7 +85,7 @@ class AgileChartsController < ApplicationController
private
def render_data(options = {})
- agile_chart = RedmineAgile::Charts::AGILE_CHARTS[@chart]
+ agile_chart = RedmineAgile::Charts::Helper::AGILE_CHARTS[@chart]
data = agile_chart[:class].data(@issues, options) if agile_chart
if data
diff --git a/app/controllers/agile_charts_queries_controller.rb b/app/controllers/agile_charts_queries_controller.rb
index 6dc6fa0..fcebd28 100644
--- a/app/controllers/agile_charts_queries_controller.rb
+++ b/app/controllers/agile_charts_queries_controller.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/app/controllers/agile_journal_details_controller.rb b/app/controllers/agile_journal_details_controller.rb
index 3d2c6c0..8fdc24c 100644
--- a/app/controllers/agile_journal_details_controller.rb
+++ b/app/controllers/agile_journal_details_controller.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/app/helpers/agile_boards_helper.rb b/app/helpers/agile_boards_helper.rb
index 5a11b6f..2a97ab2 100644
--- a/app/helpers/agile_boards_helper.rb
+++ b/app/helpers/agile_boards_helper.rb
@@ -3,7 +3,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/app/helpers/agile_charts_helper.rb b/app/helpers/agile_charts_helper.rb
index 679997a..4484997 100644
--- a/app/helpers/agile_charts_helper.rb
+++ b/app/helpers/agile_charts_helper.rb
@@ -3,7 +3,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/app/helpers/agile_support_helper.rb b/app/helpers/agile_support_helper.rb
index aba1c22..b063766 100644
--- a/app/helpers/agile_support_helper.rb
+++ b/app/helpers/agile_support_helper.rb
@@ -3,7 +3,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/app/models/agile_charts_query.rb b/app/models/agile_charts_query.rb
index 05d8a2d..63a5aae 100644
--- a/app/models/agile_charts_query.rb
+++ b/app/models/agile_charts_query.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
@@ -53,7 +53,7 @@ class AgileChartsQuery < AgileQuery
end
def chart
- @chart ||= RedmineAgile::Charts.valid_chart_name_by(options[:chart])
+ @chart ||= RedmineAgile::Charts::Helper.valid_chart_name_by(options[:chart])
end
def chart=(arg)
@@ -69,10 +69,10 @@ class AgileChartsQuery < AgileQuery
end
def interval_size
- if RedmineAgile::AgileChart::TIME_INTERVALS.include?(options[:interval_size])
+ if RedmineAgile::Charts::AgileChart::TIME_INTERVALS.include?(options[:interval_size])
options[:interval_size]
else
- RedmineAgile::AgileChart::DAY_INTERVAL
+ RedmineAgile::Charts::AgileChart::DAY_INTERVAL
end
end
@@ -94,8 +94,8 @@ class AgileChartsQuery < AgileQuery
self.date_from = params[:date_from] || (params[:query] && params[:query][:date_from])
self.date_to = params[:date_to] || (params[:query] && params[:query][:date_to])
self.chart = params[:chart] || (params[:query] && params[:query][:chart]) || params[:default_chart] || RedmineAgile.default_chart
- self.interval_size = params[:interval_size] || (params[:query] && params[:query][:interval_size]) || RedmineAgile::AgileChart::DAY_INTERVAL
- self.chart_unit = params[:chart_unit] || (params[:query] && params[:query][:chart_unit]) || RedmineAgile::Charts::UNIT_ISSUES
+ self.interval_size = params[:interval_size] || (params[:query] && params[:query][:interval_size]) || RedmineAgile::Charts::AgileChart::DAY_INTERVAL
+ self.chart_unit = params[:chart_unit] || (params[:query] && params[:query][:chart_unit]) || RedmineAgile::Charts::Helper::UNIT_ISSUES
self
end
diff --git a/app/models/agile_data.rb b/app/models/agile_data.rb
index 87db483..8a159a2 100755
--- a/app/models/agile_data.rb
+++ b/app/models/agile_data.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/app/models/agile_query.rb b/app/models/agile_query.rb
index 2b07d26..79bff3d 100644
--- a/app/models/agile_query.rb
+++ b/app/models/agile_query.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
@@ -120,7 +120,7 @@ class AgileQuery < Query
end
def chart_unit
- @chart_unit ||= RedmineAgile::Charts.valid_chart_unit_by(options[:chart], options[:chart_unit])
+ @chart_unit ||= RedmineAgile::Charts::Helper.valid_chart_unit_by(options[:chart], options[:chart_unit])
end
def chart_unit=(value)
diff --git a/app/models/agile_statuses_collector.rb b/app/models/agile_statuses_collector.rb
index b2b0673..21a679f 100644
--- a/app/models/agile_statuses_collector.rb
+++ b/app/models/agile_statuses_collector.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/app/views/agile_charts/_versions_show.html.erb b/app/views/agile_charts/_versions_show.html.erb
index 79c9725..a7b179d 100644
--- a/app/views/agile_charts/_versions_show.html.erb
+++ b/app/views/agile_charts/_versions_show.html.erb
@@ -13,7 +13,7 @@
- <%= render_agile_chart(RedmineAgile::Charts.valid_chart_name_by(params[:chart] || RedmineAgile.default_chart), @version.fixed_issues) %>
+ <%= render_agile_chart(RedmineAgile::Charts::Helper.valid_chart_name_by(params[:chart] || RedmineAgile.default_chart), @version.fixed_issues) %>
<% end %>
@@ -24,7 +24,7 @@
<% end %>
<%= javascript_tag do %>
- var chartsWithUnits = <%= raw RedmineAgile::Charts::CHARTS_WITH_UNITS.to_json %>
+ var chartsWithUnits = <%= raw RedmineAgile::Charts::Helper::CHARTS_WITH_UNITS.to_json %>
$(document).ready(function() {
toggleChartUnit($('#chart_by_select').val(), 'chart-unit-row');
});
diff --git a/app/views/agile_charts/show.html.erb b/app/views/agile_charts/show.html.erb
index a92392f..1afa732 100644
--- a/app/views/agile_charts/show.html.erb
+++ b/app/views/agile_charts/show.html.erb
@@ -29,7 +29,7 @@
<%= l(:label_agile_interval_size) %> |
- <%= select_tag 'interval_size', options_for_select(RedmineAgile::AgileChart::TIME_INTERVALS.map { |i| [l(:"label_agile_#{i}"), i] }, @query.interval_size) %>
+ <%= select_tag 'interval_size', options_for_select(RedmineAgile::Charts::AgileChart::TIME_INTERVALS.map { |i| [l(:"label_agile_#{i}"), i] }, @query.interval_size) %>
|
@@ -58,7 +58,7 @@
<% end %>
<%= javascript_tag do %>
- var chartsWithUnits = <%= raw RedmineAgile::Charts::CHARTS_WITH_UNITS.to_json %>
+ var chartsWithUnits = <%= raw RedmineAgile::Charts::Helper::CHARTS_WITH_UNITS.to_json %>
$(document).ready(function() {
toggleChartUnit($('#chart').val(), 'chart-unit-row');
/* Hide chart_period checkbox so that it couldn't be unchecked */
diff --git a/assets/javascripts/redmine_agile.js b/assets/javascripts/redmine_agile.js
index 956bcae..58a385d 100755
--- a/assets/javascripts/redmine_agile.js
+++ b/assets/javascripts/redmine_agile.js
@@ -630,7 +630,9 @@ function recalculateSprintHours() {
hours = parseFloat($(issue).data(dataAttr));
versionEstimationSum += hours;
});
- $(elem).find('.sprint-estimate').text('(' + versionEstimationSum.toFixed(2) + unit + ')');
+ if (versionEstimationSum > 0) {
+ $(elem).find('.sprint-estimate').text('(' + versionEstimationSum.toFixed(2) + unit + ')');
+ }
});
}
diff --git a/assets/stylesheets/redmine_agile.css b/assets/stylesheets/redmine_agile.css
index d8ce691..5327767 100755
--- a/assets/stylesheets/redmine_agile.css
+++ b/assets/stylesheets/redmine_agile.css
@@ -576,6 +576,16 @@ table.list.issues-board.sticky {
margin-top: -2.3em;
}
+.controller-agile_boards .observed-desc {
+ margin-top: 0;
+ display: flex;
+ justify-content: end;
+}
+
+.agile-sprint-description {
+ margin-right: auto;
+}
+
.agile-board-fullscreen .controller-agile_boards .query-totals {
margin: 0px;
position: fixed;
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 19a38ca..7bc0d18 100755
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -198,6 +198,8 @@ en:
label_agile_board_totals_velocity: Velocity
label_agile_board_totals_interval: Interval
label_agile_board_totals_remaining: Remaining
+ label_agile_board_totals_description: Sprint goal
+
label_agile_sprint_list_active: Active sprints
label_agile_sprint_list_future: Future sprints
diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml
index 5580ab7..4b5ee97 100644
--- a/config/locales/pt-BR.yml
+++ b/config/locales/pt-BR.yml
@@ -208,7 +208,7 @@ pt-BR:
label_agile_board_backlog: Backlog
label_agile_board_backlog_column: Colunas do Backlog
label_agile_board_search_backlog_issues: Pesquisar tarefas do backlog
- label_agile_version_plural: Vesões
+ label_agile_version_plural: Versões
label_agile_sprint_add: Adicionar novo Sprint
label_agile_version_add: Adicionar Versão
diff --git a/config/locales/ru.yml b/config/locales/ru.yml
index c7e21a0..ee75f8d 100755
--- a/config/locales/ru.yml
+++ b/config/locales/ru.yml
@@ -189,6 +189,7 @@ ru:
label_agile_board_totals_spent_time: Потраченное время
label_agile_board_totals_percent_done: Готовность (%)
label_agile_board_totals_velocity: Скорость закрытия
+ label_agile_board_totals_description: Цель спринта
label_agile_sprint_list_active: Активные спринты
label_agile_sprint_list_future: Следующие спринты
diff --git a/config/routes.rb b/config/routes.rb
index 21dc7b9..10be89d 100755
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/db/migrate/001_create_issue_status_orders.rb b/db/migrate/001_create_issue_status_orders.rb
index c345ce3..2b34c2c 100755
--- a/db/migrate/001_create_issue_status_orders.rb
+++ b/db/migrate/001_create_issue_status_orders.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/db/migrate/002_create_agile_colors.rb b/db/migrate/002_create_agile_colors.rb
index 1e705e8..42497e2 100644
--- a/db/migrate/002_create_agile_colors.rb
+++ b/db/migrate/002_create_agile_colors.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/db/migrate/003_rename_issue_status_orders.rb b/db/migrate/003_rename_issue_status_orders.rb
index c21e129..6889a83 100644
--- a/db/migrate/003_rename_issue_status_orders.rb
+++ b/db/migrate/003_rename_issue_status_orders.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/db/migrate/004_rename_agile_ranks.rb b/db/migrate/004_rename_agile_ranks.rb
index de7b86f..1d509c4 100644
--- a/db/migrate/004_rename_agile_ranks.rb
+++ b/db/migrate/004_rename_agile_ranks.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/db/migrate/005_add_story_points_to_agile_ranks.rb b/db/migrate/005_add_story_points_to_agile_ranks.rb
index 16ef93d..3f3db2d 100644
--- a/db/migrate/005_add_story_points_to_agile_ranks.rb
+++ b/db/migrate/005_add_story_points_to_agile_ranks.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/db/migrate/006_create_agile_sprints.rb b/db/migrate/006_create_agile_sprints.rb
index 59cac7f..2d015c3 100644
--- a/db/migrate/006_create_agile_sprints.rb
+++ b/db/migrate/006_create_agile_sprints.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/db/migrate/007_add_sprint_id_to_agile_data.rb b/db/migrate/007_add_sprint_id_to_agile_data.rb
index 5fc4159..dd54ff4 100644
--- a/db/migrate/007_add_sprint_id_to_agile_data.rb
+++ b/db/migrate/007_add_sprint_id_to_agile_data.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/db/migrate/008_add_sharing_to_agile_sprint.rb b/db/migrate/008_add_sharing_to_agile_sprint.rb
index 0df6426..d2ff55f 100644
--- a/db/migrate/008_add_sharing_to_agile_sprint.rb
+++ b/db/migrate/008_add_sharing_to_agile_sprint.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/doc/CHANGELOG b/doc/CHANGELOG
index 7345bda..ce2058d 100755
--- a/doc/CHANGELOG
+++ b/doc/CHANGELOG
@@ -1,9 +1,21 @@
== Redmine Agile plugin changelog
Redmine Agile plugin - Agile board plugin for redmine
-Copyright (C) 2011-2021 RedmineUP
+Copyright (C) 2011-2022 RedmineUP
http://www.redmineup.com/
+== 2022-03-30 v1.6.3
+
+* Redmine 5.0 compatibility
+* Added sprint description to a board view
+* Changed Manage board permissions behavior
+* Fixed default board setting
+* Fixed card load error
+* Fixed empty sprint for default board
+* Fixed saved query bug for agile board
+* Fixed story points are not being added up in "Sprints" subtab of "Backlog" tab
+* Fixed error with empty sprint_id in AgileQuery
+
== 2021-09-07 v1.6.2
* Added notification message for not available operations on Backlog board
diff --git a/init.rb b/init.rb
index c6ff7ee..b10f42b 100755
--- a/init.rb
+++ b/init.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
@@ -17,11 +17,11 @@
# You should have received a copy of the GNU General Public License
# along with redmine_agile. If not, see .
-requires_redmine_crm version_or_higher: '0.0.43' rescue raise "\n\033[31mRedmine requires newer redmine_crm gem version.\nPlease update with 'bundle update redmine_crm'.\033[0m"
+requires_redmine_crm version_or_higher: '0.0.56' rescue raise "\n\033[31mRedmine requires newer redmine_crm gem version.\nPlease update with 'bundle update redmine_crm'.\033[0m"
require 'redmine'
-AGILE_VERSION_NUMBER = '1.6.2'
+AGILE_VERSION_NUMBER = '1.6.3'
AGILE_VERSION_TYPE = "Light version"
if ActiveRecord::VERSION::MAJOR >= 4 && !defined?(FCSV)
@@ -68,4 +68,7 @@ Redmine::Plugin.register :redmine_agile do
end
end
-require 'redmine_agile'
+if Rails.configuration.respond_to?(:autoloader) && Rails.configuration.autoloader == :zeitwerk
+ Rails.autoloaders.each { |loader| loader.ignore(File.dirname(__FILE__) + '/lib') }
+end
+require File.dirname(__FILE__) + '/lib/redmine_agile'
diff --git a/lib/redmine_agile.rb b/lib/redmine_agile.rb
index ee45db0..5ddd2b6 100755
--- a/lib/redmine_agile.rb
+++ b/lib/redmine_agile.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
@@ -17,22 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with redmine_agile. If not, see .
-
-
-require 'redmine_agile/hooks/views_layouts_hook'
-require 'redmine_agile/hooks/views_issues_hook'
-require 'redmine_agile/hooks/views_versions_hook'
-require 'redmine_agile/hooks/controller_issue_hook'
-require 'redmine_agile/patches/issue_patch'
-
-require 'redmine_agile/helpers/agile_helper'
-
-require 'redmine_agile/charts/agile_chart'
-require 'redmine_agile/charts/burndown_chart'
-require 'redmine_agile/charts/work_burndown_chart'
-require 'redmine_agile/charts/charts'
-require 'redmine_agile/patches/issue_drop_patch'
-
module RedmineAgile
ISSUES_PER_COLUMN = 10
@@ -64,7 +48,7 @@ module RedmineAgile
end
def default_chart
- Setting.plugin_redmine_agile['default_chart'] || Charts::BURNDOWN_CHART
+ Setting.plugin_redmine_agile['default_chart'] || Charts::Helper::BURNDOWN_CHART
end
def estimate_units
@@ -135,3 +119,22 @@ module RedmineAgile
end
end
+
+REDMINE_AGILE_REQUIRED_FILES = [
+ 'redmine_agile/hooks/views_layouts_hook',
+ 'redmine_agile/hooks/views_issues_hook',
+ 'redmine_agile/hooks/views_versions_hook',
+ 'redmine_agile/hooks/controller_issue_hook',
+ 'redmine_agile/patches/issue_patch',
+ 'redmine_agile/helpers/agile_helper',
+ 'redmine_agile/charts/helper',
+ 'redmine_agile/charts/agile_chart',
+ 'redmine_agile/charts/burndown_chart',
+ 'redmine_agile/charts/work_burndown_chart',
+ 'redmine_agile/patches/issue_drop_patch'
+]
+
+Rails.application.config.after_initialize do
+ base_url = File.dirname(__FILE__)
+ REDMINE_AGILE_REQUIRED_FILES.each { |file| require(base_url + '/' + file) }
+end
diff --git a/lib/redmine_agile/charts/agile_chart.rb b/lib/redmine_agile/charts/agile_chart.rb
index 0a7c1db..1f84a8b 100644
--- a/lib/redmine_agile/charts/agile_chart.rb
+++ b/lib/redmine_agile/charts/agile_chart.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
@@ -18,262 +18,264 @@
# along with redmine_agile. If not, see .
module RedmineAgile
- class AgileChart
- include Redmine::I18n
- include Redmine::Utils::DateCalculation
+ module Charts
+ class AgileChart
+ include Redmine::I18n
+ include Redmine::Utils::DateCalculation
- DAY_INTERVAL = 'day'.freeze
- WEEK_INTERVAL = 'week'.freeze
- MONTH_INTERVAL = 'month'.freeze
- QUARTER_INTERVAL = 'quarter'.freeze
- YEAR_INTERVAL = 'year'.freeze
+ DAY_INTERVAL = 'day'.freeze
+ WEEK_INTERVAL = 'week'.freeze
+ MONTH_INTERVAL = 'month'.freeze
+ QUARTER_INTERVAL = 'quarter'.freeze
+ YEAR_INTERVAL = 'year'.freeze
- TIME_INTERVALS = [DAY_INTERVAL, WEEK_INTERVAL, MONTH_INTERVAL, QUARTER_INTERVAL, YEAR_INTERVAL].freeze
+ TIME_INTERVALS = [DAY_INTERVAL, WEEK_INTERVAL, MONTH_INTERVAL, QUARTER_INTERVAL, YEAR_INTERVAL].freeze
- attr_reader :line_colors
+ attr_reader :line_colors
- def initialize(data_scope, options = {})
- @options = options
- @data_scope = data_scope
- @data_from ||= options[:data_from]
- @data_to ||= options[:data_to]
- @interval_size = options[:interval_size] || DAY_INTERVAL
- initialize_chart_periods
- @step_x_labels = @period_count > 18 ? @period_count / 12 + 1 : 1
- @fields = chart_fields_by_period
- @weekend_periods = weekend_periods
- @estimated_unit = options[:estimated_unit] || ESTIMATE_HOURS
- @line_colors = {}
- end
+ def initialize(data_scope, options = {})
+ @options = options
+ @data_scope = data_scope
+ @data_from ||= options[:data_from]
+ @data_to ||= options[:data_to]
+ @interval_size = options[:interval_size] || DAY_INTERVAL
+ initialize_chart_periods
+ @step_x_labels = @period_count > 18 ? @period_count / 12 + 1 : 1
+ @fields = chart_fields_by_period
+ @weekend_periods = weekend_periods
+ @estimated_unit = options[:estimated_unit] || ESTIMATE_HOURS
+ @line_colors = {}
+ end
- def data
- { title: '', y_title: '', labels: [], datasets: [] }
- end
+ def data
+ { title: '', y_title: '', labels: [], datasets: [] }
+ end
- def self.data(data_scope, options = {})
- new(data_scope, options).data
- end
+ def self.data(data_scope, options = {})
+ new(data_scope, options).data
+ end
- protected
+ protected
- def current_date_period
- return @current_date_period if @current_date_period
+ def current_date_period
+ return @current_date_period if @current_date_period
- for_future = RedmineAgile.chart_future_data? ? @options[:date_to].present? : false
- date_period = (@date_to <= Date.today || for_future ? @period_count : (@period_count - (@date_to - Date.today).to_i / @scale_division)).round
- @current_date_period ||= date_period > 0 ? date_period : 0
- end
+ for_future = RedmineAgile.chart_future_data? ? @options[:date_to].present? : false
+ date_period = (@date_to <= Date.today || for_future ? @period_count : (@period_count - (@date_to - Date.today).to_i / @scale_division)).round
+ @current_date_period ||= date_period > 0 ? date_period : 0
+ end
- def due_date_period
- @date_from = @date_from.to_date
- @date_to = @date_to.to_date
- due_date = (@due_date && @due_date > @date_from) ? @due_date : @date_from
- @due_date_period ||= (@due_date ? @period_count - (@date_to - due_date.to_date).to_i : @period_count - 1)
- @due_date_period = @due_date_period > 0 ? @due_date_period : 1
- end
+ def due_date_period
+ @date_from = @date_from.to_date
+ @date_to = @date_to.to_date
+ due_date = (@due_date && @due_date > @date_from) ? @due_date : @date_from
+ @due_date_period ||= (@due_date ? @period_count - (@date_to - due_date.to_date).to_i : @period_count - 1)
+ @due_date_period = @due_date_period > 0 ? @due_date_period : 1
+ end
- def date_short_period?
- (@date_to.to_date - @date_from.to_date).to_i <= 31
- end
+ def date_short_period?
+ (@date_to.to_date - @date_from.to_date).to_i <= 31
+ end
- def date_effort(issues, effort_date)
- cumulative_left = 0
- total_left = 0
- total_done = 0
- issues.each do |issue|
- done_ratio_details = issue.journals.map(&:details).flatten.select { |detail| 'done_ratio' == detail.prop_key }
- details_today_or_earlier = done_ratio_details.select { |a| a.journal.created_on.localtime.to_date <= effort_date }
+ def date_effort(issues, effort_date)
+ cumulative_left = 0
+ total_left = 0
+ total_done = 0
+ issues.each do |issue|
+ done_ratio_details = issue.journals.map(&:details).flatten.select { |detail| 'done_ratio' == detail.prop_key }
+ details_today_or_earlier = done_ratio_details.select { |a| a.journal.created_on.localtime.to_date <= effort_date }
- last_done_ratio_change = details_today_or_earlier.sort_by { |a| a.journal.created_on }.last
- ratio = if issue.closed? && issue.closed_on.localtime.to_date <= effort_date
- 100
- elsif last_done_ratio_change
- last_done_ratio_change.value
- elsif (done_ratio_details.size > 0) || (issue.closed? && issue.closed_on > effort_date)
- 0
- else
- issue.done_ratio.to_i
- end
+ last_done_ratio_change = details_today_or_earlier.sort_by { |a| a.journal.created_on }.last
+ ratio = if issue.closed? && issue.closed_on.localtime.to_date <= effort_date
+ 100
+ elsif last_done_ratio_change
+ last_done_ratio_change.value
+ elsif (done_ratio_details.size > 0) || (issue.closed? && issue.closed_on > effort_date)
+ 0
+ else
+ issue.done_ratio.to_i
+ end
- if @estimated_unit == 'hours'
- cumulative_left += (issue.estimated_hours.to_f * ratio.to_f / 100.0)
- total_left += (issue.estimated_hours.to_f * (100 - ratio.to_f) / 100.0)
- total_done += (issue.estimated_hours.to_f * ratio.to_f / 100.0)
+ if @estimated_unit == 'hours'
+ cumulative_left += (issue.estimated_hours.to_f * ratio.to_f / 100.0)
+ total_left += (issue.estimated_hours.to_f * (100 - ratio.to_f) / 100.0)
+ total_done += (issue.estimated_hours.to_f * ratio.to_f / 100.0)
+ else
+ cumulative_left += (issue.story_points.to_f * ratio.to_f / 100.0)
+ total_left += (issue.story_points.to_f * (100 - ratio.to_f) / 100.0)
+ total_done += (issue.story_points.to_f * ratio.to_f / 100.0)
+ end
+ end
+ [total_left, cumulative_left, total_done]
+ end
+
+ def use_subissue_done_ratio
+ !Setting.respond_to?(:parent_issue_done_ratio) || Setting.parent_issue_done_ratio == 'derived' || Setting.parent_issue_done_ratio.nil?
+ end
+
+ private
+
+ def scope_by_created_date
+ @data_scope.
+ where("#{Issue.table_name}.created_on >= ?", @date_from).
+ where("#{Issue.table_name}.created_on < ?", @date_to.to_date + 1).
+ where("#{Issue.table_name}.created_on IS NOT NULL").
+ group("#{Issue.table_name}.created_on").
+ count
+ end
+
+ def scope_by_closed_date
+ @data_scope.
+ open(false).
+ where("#{Issue.table_name}.closed_on >= ?", @date_from).
+ where("#{Issue.table_name}.closed_on < ?", @date_to.to_date + 1).
+ where("#{Issue.table_name}.closed_on IS NOT NULL").
+ group("#{Issue.table_name}.closed_on").
+ count
+ end
+
+ # options
+ # color - Line color in RGB format (e.g '255,255,255') (random)
+ # fill - Fille background under line (false)
+ # dashed - Draw dached line (solid)
+ # nopoints - Doesn't show points on line (false)
+
+ def dataset(dataset_data, label, options = {})
+ color = options[:color] || [rand(255), rand(255), rand(255)].join(',')
+ dataset_color = "rgba(#{color}, 1)"
+ {
+ type: (options[:type] || 'line'),
+ data: dataset_data,
+ label: label,
+ fill: (options[:fill] || false),
+ backgroundColor: "rgba(#{color}, 0.2)",
+ borderColor: dataset_color,
+ borderDash: (options[:dashed] ? [5, 5] : []),
+ borderWidth: (options[:dashed] ? 1.5 : 2),
+ pointRadius: (options[:nopoints] ? 0 : 3),
+ pointBackgroundColor: dataset_color,
+ tooltips: { enable: false }
+ }
+ end
+
+ def initialize_chart_periods
+ raise Exception "Dates can't be blank" if [@date_to, @date_from].any?(&:blank?)
+ period_count
+ scale_division
+ end
+
+ def issues_count_by_period(issues_scope)
+ data = [0] * @period_count
+ issues_scope.each do |c|
+ next if c.first.localtime.to_date > @date_to.to_date
+ period_num = ((@date_to.to_date - c.first.localtime.to_date).to_i / @scale_division).to_i
+ data[period_num] += c.last unless data[period_num].blank?
+ end
+ data.reverse
+ end
+
+ def issues_avg_count_by_period(issues_scope)
+ count_by_date = {}
+ issues_scope.each {|x, y| count_by_date[x.localtime.to_date] = count_by_date[x.localtime.to_date].to_i + y }
+ data = [0] * @period_count
+ count_by_date.each do |x, y|
+ next if x.to_date > @date_to.to_date
+ period_num = ((@date_to.to_date - x.to_date).to_i / @scale_division).to_i
+ if data[period_num]
+ data[period_num] = y unless data[period_num].to_i > 0
+ data[period_num] = (data[period_num] + y) / 2.0
+ end
+ end
+ data.reverse
+ end
+
+ def chart_fields_by_period
+ chart_dates_by_period.map { |d| chart_field_by_date(d) }
+ end
+
+ def chart_field_by_date(date)
+ case @interval_size
+ when YEAR_INTERVAL
+ date.year
+ when QUARTER_INTERVAL, MONTH_INTERVAL
+ month_abbr_name(date.month) + ' ' + date.year.to_s
else
- cumulative_left += (issue.story_points.to_f * ratio.to_f / 100.0)
- total_left += (issue.story_points.to_f * (100 - ratio.to_f) / 100.0)
- total_done += (issue.story_points.to_f * ratio.to_f / 100.0)
+ date.day.to_s + ' ' + month_name(date.month)
end
end
- [total_left, cumulative_left, total_done]
- end
- def use_subissue_done_ratio
- !Setting.respond_to?(:parent_issue_done_ratio) || Setting.parent_issue_done_ratio == 'derived' || Setting.parent_issue_done_ratio.nil?
- end
-
- private
-
- def scope_by_created_date
- @data_scope.
- where("#{Issue.table_name}.created_on >= ?", @date_from).
- where("#{Issue.table_name}.created_on < ?", @date_to.to_date + 1).
- where("#{Issue.table_name}.created_on IS NOT NULL").
- group("#{Issue.table_name}.created_on").
- count
- end
-
- def scope_by_closed_date
- @data_scope.
- open(false).
- where("#{Issue.table_name}.closed_on >= ?", @date_from).
- where("#{Issue.table_name}.closed_on < ?", @date_to.to_date + 1).
- where("#{Issue.table_name}.closed_on IS NOT NULL").
- group("#{Issue.table_name}.closed_on").
- count
- end
-
- # options
- # color - Line color in RGB format (e.g '255,255,255') (random)
- # fill - Fille background under line (false)
- # dashed - Draw dached line (solid)
- # nopoints - Doesn't show points on line (false)
-
- def dataset(dataset_data, label, options = {})
- color = options[:color] || [rand(255), rand(255), rand(255)].join(',')
- dataset_color = "rgba(#{color}, 1)"
- {
- type: (options[:type] || 'line'),
- data: dataset_data,
- label: label,
- fill: (options[:fill] || false),
- backgroundColor: "rgba(#{color}, 0.2)",
- borderColor: dataset_color,
- borderDash: (options[:dashed] ? [5, 5] : []),
- borderWidth: (options[:dashed] ? 1.5 : 2),
- pointRadius: (options[:nopoints] ? 0 : 3),
- pointBackgroundColor: dataset_color,
- tooltips: { enable: false }
- }
- end
-
- def initialize_chart_periods
- raise Exception "Dates can't be blank" if [@date_to, @date_from].any?(&:blank?)
- period_count
- scale_division
- end
-
- def issues_count_by_period(issues_scope)
- data = [0] * @period_count
- issues_scope.each do |c|
- next if c.first.localtime.to_date > @date_to.to_date
- period_num = ((@date_to.to_date - c.first.localtime.to_date).to_i / @scale_division).to_i
- data[period_num] += c.last unless data[period_num].blank?
- end
- data.reverse
- end
-
- def issues_avg_count_by_period(issues_scope)
- count_by_date = {}
- issues_scope.each {|x, y| count_by_date[x.localtime.to_date] = count_by_date[x.localtime.to_date].to_i + y }
- data = [0] * @period_count
- count_by_date.each do |x, y|
- next if x.to_date > @date_to.to_date
- period_num = ((@date_to.to_date - x.to_date).to_i / @scale_division).to_i
- if data[period_num]
- data[period_num] = y unless data[period_num].to_i > 0
- data[period_num] = (data[period_num] + y) / 2.0
+ def weekend_periods
+ periods = []
+ @period_count.times do |m|
+ period_date = ((@date_to.to_date - 1 - m * @scale_division) + 1)
+ periods << @period_count - m - 1 if non_working_week_days.include?(period_date.cwday)
end
- end
- data.reverse
- end
-
- def chart_fields_by_period
- chart_dates_by_period.map { |d| chart_field_by_date(d) }
- end
-
- def chart_field_by_date(date)
- case @interval_size
- when YEAR_INTERVAL
- date.year
- when QUARTER_INTERVAL, MONTH_INTERVAL
- month_abbr_name(date.month) + ' ' + date.year.to_s
- else
- date.day.to_s + ' ' + month_name(date.month)
- end
- end
-
- def weekend_periods
- periods = []
- @period_count.times do |m|
- period_date = ((@date_to.to_date - 1 - m * @scale_division) + 1)
- periods << @period_count - m - 1 if non_working_week_days.include?(period_date.cwday)
- end
- periods.compact
- end
-
- def chart_data_pairs(chart_data)
- chart_data.inject([]) { |accum, value| accum << value }
- data_pairs = []
- for i in 0..chart_data.count - 1
- data_pairs << [chart_dates_by_period[i], chart_data[i]]
- end
- data_pairs
- end
-
- def chart_dates_by_period
- return @chart_dates_by_period if @chart_dates_by_period
-
- period = period_count > 1 ? period_count - 1 : period_count
- @chart_dates_by_period ||= period.times.inject([]) do |accum, m|
- period_date = ((@date_to.to_date - 1 - m * @scale_division) + 1)
- accum << if @interval_size == WEEK_INTERVAL
- period_date.at_beginning_of_week.to_date
- else
- period_date.to_date
- end
- end.reverse
- end
-
- def month_abbr_name(month)
- l('date.abbr_month_names')[month]
- end
-
- def trendline(y_values)
- size = y_values.size
- x_values = (1..size).to_a
- sum_x = 0
- sum_y = 0
- sum_xx = 0
- sum_xy = 0
- y_values.zip(x_values).each do |y, x|
- sum_xy += x * y
- sum_xx += x * x
- sum_x += x
- sum_y += y
+ periods.compact
end
- slope = 1.0 * ((size * sum_xy) - (sum_x * sum_y)) / ((size * sum_xx) - (sum_x * sum_x))
- intercept = 1.0 * (sum_y - (slope * sum_x)) / size
+ def chart_data_pairs(chart_data)
+ chart_data.inject([]) { |accum, value| accum << value }
+ data_pairs = []
+ for i in 0..chart_data.count - 1
+ data_pairs << [chart_dates_by_period[i], chart_data[i]]
+ end
+ data_pairs
+ end
- line_values = x_values.map { |x| predict(x, slope, intercept) }
- line_values.select { |val| val >= 0 }
- end
+ def chart_dates_by_period
+ return @chart_dates_by_period if @chart_dates_by_period
- def predict(x, slope, intercept)
- slope * x + intercept
- end
+ period = period_count > 1 ? period_count - 1 : period_count
+ @chart_dates_by_period ||= period.times.inject([]) do |accum, m|
+ period_date = ((@date_to.to_date - 1 - m * @scale_division) + 1)
+ accum << if @interval_size == WEEK_INTERVAL
+ period_date.at_beginning_of_week.to_date
+ else
+ period_date.to_date
+ end
+ end.reverse
+ end
- def period_count
- @period_count ||= ((@date_to.to_time - @date_from.to_time) / time_divider).round + 1
- end
+ def month_abbr_name(month)
+ l('date.abbr_month_names')[month]
+ end
- def scale_division
- @scale_division ||= time_divider / 1.day
- end
+ def trendline(y_values)
+ size = y_values.size
+ x_values = (1..size).to_a
+ sum_x = 0
+ sum_y = 0
+ sum_xx = 0
+ sum_xy = 0
+ y_values.zip(x_values).each do |y, x|
+ sum_xy += x * y
+ sum_xx += x * x
+ sum_x += x
+ sum_y += y
+ end
- def time_divider
- @interval_size == QUARTER_INTERVAL ? 3.months : 1.send(@interval_size)
+ slope = 1.0 * ((size * sum_xy) - (sum_x * sum_y)) / ((size * sum_xx) - (sum_x * sum_x))
+ intercept = 1.0 * (sum_y - (slope * sum_x)) / size
+
+ line_values = x_values.map { |x| predict(x, slope, intercept) }
+ line_values.select { |val| val >= 0 }
+ end
+
+ def predict(x, slope, intercept)
+ slope * x + intercept
+ end
+
+ def period_count
+ @period_count ||= ((@date_to.to_time - @date_from.to_time) / time_divider).round + 1
+ end
+
+ def scale_division
+ @scale_division ||= time_divider / 1.day
+ end
+
+ def time_divider
+ @interval_size == QUARTER_INTERVAL ? 3.months : 1.send(@interval_size)
+ end
end
end
end
diff --git a/lib/redmine_agile/charts/burndown_chart.rb b/lib/redmine_agile/charts/burndown_chart.rb
index 6a21a57..e29e55f 100644
--- a/lib/redmine_agile/charts/burndown_chart.rb
+++ b/lib/redmine_agile/charts/burndown_chart.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
@@ -18,95 +18,97 @@
# along with redmine_agile. If not, see .
module RedmineAgile
- class BurndownChart < AgileChart
- attr_accessor :burndown_data, :cumulative_burndown_data
+ module Charts
+ class BurndownChart < AgileChart
+ attr_accessor :burndown_data, :cumulative_burndown_data
- def initialize(data_scope, options = {})
- @date_from = options[:date_from] && options[:date_from].to_date ||
- [data_scope.minimum("#{Issue.table_name}.created_on"),
- data_scope.minimum("#{Issue.table_name}.start_date")].compact.map(&:to_date).min
+ def initialize(data_scope, options = {})
+ @date_from = options[:date_from] && options[:date_from].to_date ||
+ [data_scope.minimum("#{Issue.table_name}.created_on"),
+ data_scope.minimum("#{Issue.table_name}.start_date")].compact.map(&:to_date).min
- @date_to = options[:date_to] && options[:date_to].to_date ||
- [options[:due_date],
- data_scope.maximum("#{Issue.table_name}.updated_on")].compact.map(&:to_date).max
+ @date_to = options[:date_to] && options[:date_to].to_date ||
+ [options[:due_date],
+ data_scope.maximum("#{Issue.table_name}.updated_on")].compact.map(&:to_date).max
- @due_date = options[:due_date].to_date if options[:due_date]
- @show_ideal_effort = options[:date_from] && options[:date_to]
+ @due_date = options[:due_date].to_date if options[:due_date]
+ @show_ideal_effort = options[:date_from] && options[:date_to]
- super data_scope, options
+ super data_scope, options
- @fields = [''] + @fields
- @y_title = l(:label_agile_charts_number_of_issues)
- @graph_title = l(:label_agile_charts_issues_burndown)
- @line_colors = { :work => '80,122,170', :ideal => '102,102,102', :total => '80,122,170' }
- end
-
- def data
- return false unless calculate_burndown_data.any?
-
- datasets = [dataset(@burndown_data, l(:label_agile_actual_work_remaining), :fill => true, :color => line_colors[:work])]
- if @show_ideal_effort
- datasets << dataset(ideal_effort(@cumulative_burndown_data.first), l(:label_agile_ideal_work_remaining),
- :color => line_colors[:ideal], :dashed => true, :nopoints => true)
- end
- if @show_ideal_effort && (@cumulative_burndown_data != @burndown_data)
- datasets << dataset(@cumulative_burndown_data, l(:label_agile_total_work_remaining),
- :color => line_colors[:total], :dashed => true)
+ @fields = [''] + @fields
+ @y_title = l(:label_agile_charts_number_of_issues)
+ @graph_title = l(:label_agile_charts_issues_burndown)
+ @line_colors = { :work => '80,122,170', :ideal => '102,102,102', :total => '80,122,170' }
end
- {
- :title => @graph_title,
- :y_title => @y_title,
- :labels => @fields,
- :datasets => datasets,
- :show_tooltips => [0, 2]
- }
- end
+ def data
+ return false unless calculate_burndown_data.any?
- def self.data(data_scope, options = {})
- if options[:chart_unit] == Charts::UNIT_HOURS
- WorkBurndownChart.new(data_scope, options.merge(estimated_unit: ESTIMATE_HOURS)).data
- elsif options[:chart_unit] == Charts::UNIT_STORY_POINTS
- WorkBurndownChart.new(data_scope, options.merge(estimated_unit: ESTIMATE_STORY_POINTS)).data
- else
- super
+ datasets = [dataset(@burndown_data, l(:label_agile_actual_work_remaining), :fill => true, :color => line_colors[:work])]
+ if @show_ideal_effort
+ datasets << dataset(ideal_effort(@cumulative_burndown_data.first), l(:label_agile_ideal_work_remaining),
+ :color => line_colors[:ideal], :dashed => true, :nopoints => true)
+ end
+ if @show_ideal_effort && (@cumulative_burndown_data != @burndown_data)
+ datasets << dataset(@cumulative_burndown_data, l(:label_agile_total_work_remaining),
+ :color => line_colors[:total], :dashed => true)
+ end
+
+ {
+ :title => @graph_title,
+ :y_title => @y_title,
+ :labels => @fields,
+ :datasets => datasets,
+ :show_tooltips => [0, 2]
+ }
end
- end
- protected
-
- def ideal_effort(start_remaining)
- data = [0] * (due_date_period - 1)
- active_periods = (RedmineAgile.exclude_weekends? && date_short_period?) ? due_date_period - @weekend_periods.select { |p| p < due_date_period }.count : due_date_period
- avg_remaining_velocity = start_remaining.to_f / active_periods.to_f
- sum = start_remaining.to_f
- data[0] = sum
- (1..due_date_period - 1).each do |i|
- sum -= avg_remaining_velocity unless (RedmineAgile.exclude_weekends? && date_short_period?) && @weekend_periods.include?(i - 1)
- data[i] = (sum * 100).round / 100.0
+ def self.data(data_scope, options = {})
+ if options[:chart_unit] == Helper::UNIT_HOURS
+ WorkBurndownChart.new(data_scope, options.merge(estimated_unit: ESTIMATE_HOURS)).data
+ elsif options[:chart_unit] == Helper::UNIT_STORY_POINTS
+ WorkBurndownChart.new(data_scope, options.merge(estimated_unit: ESTIMATE_STORY_POINTS)).data
+ else
+ super
+ end
end
- data[due_date_period] = 0
- data
- end
- def calculate_burndown_data
- created_by_period = issues_count_by_period(scope_by_created_date)
- closed_by_period = issues_count_by_period(scope_by_closed_date)
+ protected
- total_issues = @data_scope.count
- total_issues_before = @data_scope.where("#{Issue.table_name}.created_on < ?", @date_from).count
- total_closed_before = @data_scope.open(false).where("#{Issue.table_name}.closed_on < ?", @date_from).count
+ def ideal_effort(start_remaining)
+ data = [0] * (due_date_period - 1)
+ active_periods = (RedmineAgile.exclude_weekends? && date_short_period?) ? due_date_period - @weekend_periods.select { |p| p < due_date_period }.count : due_date_period
+ avg_remaining_velocity = start_remaining.to_f / active_periods.to_f
+ sum = start_remaining.to_f
+ data[0] = sum
+ (1..due_date_period - 1).each do |i|
+ sum -= avg_remaining_velocity unless (RedmineAgile.exclude_weekends? && date_short_period?) && @weekend_periods.include?(i - 1)
+ data[i] = (sum * 100).round / 100.0
+ end
+ data[due_date_period] = 0
+ data
+ end
- sum = total_issues_before
- cumulative_created_by_period = created_by_period.first(current_date_period).map { |x| sum += x }
- sum = total_closed_before
- cumulative_closed_by_period = closed_by_period.first(current_date_period).map { |x| sum += x }
+ def calculate_burndown_data
+ created_by_period = issues_count_by_period(scope_by_created_date)
+ closed_by_period = issues_count_by_period(scope_by_closed_date)
- burndown_by_period = [0] * (current_date_period)
- cumulative_created_by_period.each_with_index { |e, i| burndown_by_period[i] = e - cumulative_closed_by_period[i] }
- first_day_open_issues = @data_scope.where("#{Issue.table_name}.created_on < ?", @date_from + 1).count - total_closed_before
- @cumulative_burndown_data = [total_issues - total_closed_before] + cumulative_closed_by_period.map { |c| total_issues - c }
- @burndown_data = [first_day_open_issues] + burndown_by_period
+ total_issues = @data_scope.count
+ total_issues_before = @data_scope.where("#{Issue.table_name}.created_on < ?", @date_from).count
+ total_closed_before = @data_scope.open(false).where("#{Issue.table_name}.closed_on < ?", @date_from).count
+
+ sum = total_issues_before
+ cumulative_created_by_period = created_by_period.first(current_date_period).map { |x| sum += x }
+ sum = total_closed_before
+ cumulative_closed_by_period = closed_by_period.first(current_date_period).map { |x| sum += x }
+
+ burndown_by_period = [0] * (current_date_period)
+ cumulative_created_by_period.each_with_index { |e, i| burndown_by_period[i] = e - cumulative_closed_by_period[i] }
+ first_day_open_issues = @data_scope.where("#{Issue.table_name}.created_on < ?", @date_from + 1).count - total_closed_before
+ @cumulative_burndown_data = [total_issues - total_closed_before] + cumulative_closed_by_period.map { |c| total_issues - c }
+ @burndown_data = [first_day_open_issues] + burndown_by_period
+ end
end
end
end
diff --git a/lib/redmine_agile/charts/charts.rb b/lib/redmine_agile/charts/charts.rb
deleted file mode 100644
index a2a478e..0000000
--- a/lib/redmine_agile/charts/charts.rb
+++ /dev/null
@@ -1,98 +0,0 @@
-# This file is a part of Redmin Agile (redmine_agile) plugin,
-# Agile board plugin for redmine
-#
-# Copyright (C) 2011-2021 RedmineUP
-# http://www.redmineup.com/
-#
-# redmine_agile is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# redmine_agile is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with redmine_agile. If not, see .
-
-module RedmineAgile
- module Charts
- BURNDOWN_CHART = 'burndown_chart'.freeze
- ISSUES_BURNDOWN_CHART = 'issues_burndown'.freeze
- WORK_BURNDOWN_SP_CHART = 'work_burndown_sp'.freeze
- WORK_BURNDOWN_HOURS_CHART = 'work_burndown_hours'.freeze
-
- AGILE_CHARTS = {
- BURNDOWN_CHART => { name: :label_agile_chart_burndown, class: BurndownChart,
- aliases: [ISSUES_BURNDOWN_CHART, WORK_BURNDOWN_HOURS_CHART, WORK_BURNDOWN_SP_CHART] },
- }.freeze
-
- CHARTS_WITH_UNITS = [
- BURNDOWN_CHART,
- ].freeze
-
- UNIT_ISSUES = 'issues'.freeze
- UNIT_STORY_POINTS = 'story_points'.freeze
- UNIT_HOURS = 'hours'.freeze
-
- CHART_UNITS = {
- UNIT_ISSUES => :label_issue_plural,
- UNIT_STORY_POINTS => :label_agile_story_points,
- UNIT_HOURS => :label_agile_hours
- }.freeze
-
- CHART_UNIT_BY_ALIAS = {
- ISSUES_BURNDOWN_CHART => UNIT_ISSUES,
- WORK_BURNDOWN_HOURS_CHART => UNIT_HOURS,
- WORK_BURNDOWN_SP_CHART => UNIT_STORY_POINTS,
- }
-
- def self.valid_chart?(name) !!AGILE_CHARTS[name] end
-
- def self.chart_by_alias(alias_name)
- chart_name = nil
- AGILE_CHARTS.each do |chart, value|
- if value[:aliases] && value[:aliases].include?(alias_name)
- chart_name = chart
- break
- end
- end
- chart_name
- end
-
- def self.valid_chart_name_by(old_chart_name)
- if valid_chart?(old_chart_name)
- old_chart_name
- elsif (chart_by_alias = chart_by_alias(old_chart_name))
- chart_by_alias
- else
- BURNDOWN_CHART
- end
- end
-
- def self.valid_chart_unit?(name) !!CHART_UNITS[name] end
-
- def self.chart_with_units?(old_chart_name)
- CHARTS_WITH_UNITS.include? valid_chart_name_by(old_chart_name)
- end
-
- def self.valid_chart_unit_by(old_chart_name, chart_unit)
- if chart_with_units?(old_chart_name)
- if chart_by_alias(old_chart_name)
- CHART_UNIT_BY_ALIAS[old_chart_name]
- elsif valid_chart_unit?(chart_unit)
- chart_unit
- else
- UNIT_ISSUES
- end
- end
- end
-
- def self.chart_unit_label_by(alias_name)
- chart_unit = CHART_UNIT_BY_ALIAS[alias_name]
- CHART_UNITS[chart_unit]
- end
- end
-end
diff --git a/lib/redmine_agile/charts/helper.rb b/lib/redmine_agile/charts/helper.rb
new file mode 100644
index 0000000..dc1916e
--- /dev/null
+++ b/lib/redmine_agile/charts/helper.rb
@@ -0,0 +1,100 @@
+# This file is a part of Redmin Agile (redmine_agile) plugin,
+# Agile board plugin for redmine
+#
+# Copyright (C) 2011-2022 RedmineUP
+# http://www.redmineup.com/
+#
+# redmine_agile is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# redmine_agile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with redmine_agile. If not, see .
+
+module RedmineAgile
+ module Charts
+ class Helper
+ BURNDOWN_CHART = 'burndown_chart'.freeze
+ ISSUES_BURNDOWN_CHART = 'issues_burndown'.freeze
+ WORK_BURNDOWN_SP_CHART = 'work_burndown_sp'.freeze
+ WORK_BURNDOWN_HOURS_CHART = 'work_burndown_hours'.freeze
+
+ AGILE_CHARTS = {
+ BURNDOWN_CHART => { name: :label_agile_chart_burndown, class: BurndownChart,
+ aliases: [ISSUES_BURNDOWN_CHART, WORK_BURNDOWN_HOURS_CHART, WORK_BURNDOWN_SP_CHART] },
+ }.freeze
+
+ CHARTS_WITH_UNITS = [
+ BURNDOWN_CHART,
+ ].freeze
+
+ UNIT_ISSUES = 'issues'.freeze
+ UNIT_STORY_POINTS = 'story_points'.freeze
+ UNIT_HOURS = 'hours'.freeze
+
+ CHART_UNITS = {
+ UNIT_ISSUES => :label_issue_plural,
+ UNIT_STORY_POINTS => :label_agile_story_points,
+ UNIT_HOURS => :label_agile_hours
+ }.freeze
+
+ CHART_UNIT_BY_ALIAS = {
+ ISSUES_BURNDOWN_CHART => UNIT_ISSUES,
+ WORK_BURNDOWN_HOURS_CHART => UNIT_HOURS,
+ WORK_BURNDOWN_SP_CHART => UNIT_STORY_POINTS,
+ }
+
+ def self.valid_chart?(name) !!AGILE_CHARTS[name] end
+
+ def self.chart_by_alias(alias_name)
+ chart_name = nil
+ AGILE_CHARTS.each do |chart, value|
+ if value[:aliases] && value[:aliases].include?(alias_name)
+ chart_name = chart
+ break
+ end
+ end
+ chart_name
+ end
+
+ def self.valid_chart_name_by(old_chart_name)
+ if valid_chart?(old_chart_name)
+ old_chart_name
+ elsif (chart_by_alias = chart_by_alias(old_chart_name))
+ chart_by_alias
+ else
+ BURNDOWN_CHART
+ end
+ end
+
+ def self.valid_chart_unit?(name) !!CHART_UNITS[name] end
+
+ def self.chart_with_units?(old_chart_name)
+ CHARTS_WITH_UNITS.include? valid_chart_name_by(old_chart_name)
+ end
+
+ def self.valid_chart_unit_by(old_chart_name, chart_unit)
+ if chart_with_units?(old_chart_name)
+ if chart_by_alias(old_chart_name)
+ CHART_UNIT_BY_ALIAS[old_chart_name]
+ elsif valid_chart_unit?(chart_unit)
+ chart_unit
+ else
+ UNIT_ISSUES
+ end
+ end
+ end
+
+ def self.chart_unit_label_by(alias_name)
+ chart_unit = CHART_UNIT_BY_ALIAS[alias_name]
+ CHART_UNITS[chart_unit]
+ end
+ end
+ end
+end
diff --git a/lib/redmine_agile/charts/work_burndown_chart.rb b/lib/redmine_agile/charts/work_burndown_chart.rb
index 0c8019e..19b20d0 100644
--- a/lib/redmine_agile/charts/work_burndown_chart.rb
+++ b/lib/redmine_agile/charts/work_burndown_chart.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
@@ -18,52 +18,54 @@
# along with redmine_agile. If not, see .
module RedmineAgile
- class WorkBurndownChart < BurndownChart
- def initialize(data_scope, options = {})
- super data_scope, options
- if @estimated_unit == 'hours'
- @y_title = l(:label_agile_charts_number_of_hours)
- @graph_title = l(:label_agile_charts_work_burndown_hours)
- else
- @y_title = l(:label_agile_charts_number_of_story_points)
- @graph_title = l(:label_agile_charts_work_burndown_sp)
+ module Charts
+ class WorkBurndownChart < BurndownChart
+ def initialize(data_scope, options = {})
+ super data_scope, options
+ if @estimated_unit == 'hours'
+ @y_title = l(:label_agile_charts_number_of_hours)
+ @graph_title = l(:label_agile_charts_work_burndown_hours)
+ else
+ @y_title = l(:label_agile_charts_number_of_story_points)
+ @graph_title = l(:label_agile_charts_work_burndown_sp)
+ end
+
+ @line_colors = { work: '0,153,0', ideal: '102,102,102', total: '0,153,0' }
end
- @line_colors = { work: '0,153,0', ideal: '102,102,102', total: '0,153,0' }
- end
+ protected
- protected
+ def calculate_burndown_data
+ data_scope = @data_scope
+ data_scope = data_scope.where("#{Issue.table_name}.rgt - #{Issue.table_name}.lft = 1") if use_subissue_done_ratio && @estimated_unit == 'hours'
- def calculate_burndown_data
- data_scope = @data_scope
- data_scope = data_scope.where("#{Issue.table_name}.rgt - #{Issue.table_name}.lft = 1") if use_subissue_done_ratio && @estimated_unit == 'hours'
+ if @estimated_unit == 'hours'
+ all_issues = data_scope.where("#{Issue.table_name}.estimated_hours IS NOT NULL").
+ eager_load([:journals, :status, { journals: { details: :journal } }])
+ cumulative_total_hours = data_scope.sum("#{Issue.table_name}.estimated_hours").to_f
+ else
+ all_issues = data_scope.where("#{AgileData.table_name}.story_points IS NOT NULL").
+ joins(:agile_data).eager_load([:journals, :status, { journals: { details: :journal } }])
+ cumulative_total_hours = data_scope.joins(:agile_data).sum("#{AgileData.table_name}.story_points").to_f
+ end
- if @estimated_unit == 'hours'
- all_issues = data_scope.where("#{Issue.table_name}.estimated_hours IS NOT NULL").
- eager_load([:journals, :status, { journals: { details: :journal } }])
- cumulative_total_hours = data_scope.sum("#{Issue.table_name}.estimated_hours").to_f
- else
- all_issues = data_scope.where("#{AgileData.table_name}.story_points IS NOT NULL").
- joins(:agile_data).eager_load([:journals, :status, { journals: { details: :journal } }])
- cumulative_total_hours = data_scope.joins(:agile_data).sum("#{AgileData.table_name}.story_points").to_f
+ data = chart_dates_by_period.select { |d| d <= Date.today }.map do |date|
+ issues = all_issues.select { |issue| issue.created_on.localtime.to_date <= date }
+ total_hours_left, cumulative_total_hours_left = date_effort(issues, date)
+ [total_hours_left, cumulative_total_hours - cumulative_total_hours_left]
+ end
+ tail_values = data.last ? [data.last] * (current_date_period - data.size) : []
+ data = first_period_effort(all_issues, chart_dates_by_period.first, cumulative_total_hours) + data + tail_values
+ @burndown_data, @cumulative_burndown_data = data.transpose
end
- data = chart_dates_by_period.select { |d| d <= Date.today }.map do |date|
- issues = all_issues.select { |issue| issue.created_on.localtime.to_date <= date }
- total_hours_left, cumulative_total_hours_left = date_effort(issues, date)
- [total_hours_left, cumulative_total_hours - cumulative_total_hours_left]
+ private
+
+ def first_period_effort(issues_scope, start_date, cumulative_total_hours)
+ issues = issues_scope.select { |issue| issue.created_on.localtime.to_date <= start_date }
+ total_left, cumulative_left = date_effort(issues, start_date - 1)
+ [[total_left, cumulative_total_hours - cumulative_left]]
end
- tail_values = data.last ? [data.last] * (current_date_period - data.size) : []
- data = first_period_effort(all_issues, chart_dates_by_period.first, cumulative_total_hours) + data + tail_values
- @burndown_data, @cumulative_burndown_data = data.transpose
- end
-
- private
-
- def first_period_effort(issues_scope, start_date, cumulative_total_hours)
- issues = issues_scope.select { |issue| issue.created_on.localtime.to_date <= start_date }
- total_left, cumulative_left = date_effort(issues, start_date - 1)
- [[total_left, cumulative_total_hours - cumulative_left]]
end
end
end
diff --git a/lib/redmine_agile/helpers/agile_helper.rb b/lib/redmine_agile/helpers/agile_helper.rb
index cdc4be9..cae2787 100644
--- a/lib/redmine_agile/helpers/agile_helper.rb
+++ b/lib/redmine_agile/helpers/agile_helper.rb
@@ -3,7 +3,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
@@ -20,134 +20,136 @@
# along with redmine_agile. If not, see .
module RedmineAgile
- module AgileHelper
+ module Helpers
+ module AgileHelper
- def retrieve_agile_query_from_session
- if session[:agile_query]
- if session[:agile_query][:id]
- @query = AgileQuery.find_by_id(session[:agile_query][:id])
- return unless @query
- else
- @query = AgileQuery.new(get_query_attributes_from_session)
- end
- if session[:agile_query].has_key?(:project_id)
- @query.project_id = session[:agile_query][:project_id]
- else
- @query.project = @project
- end
- @query
- else
- @query = AgileQuery.new(:name => "_")
- end
- end
-
- def retrieve_agile_query
- if !params[:query_id].blank?
- cond = "project_id IS NULL"
- cond << " OR project_id = #{@project.id}" if @project
- @query = AgileQuery.where(cond).find(params[:query_id])
- raise ::Unauthorized unless @query.visible?
- @query.project = @project
- session[:agile_query] = {:id => @query.id, :project_id => @query.project_id}
- sort_clear
- elsif api_request? || params[:set_filter] || session[:agile_query].nil? || session[:agile_query][:project_id] != (@project ? @project.id : nil)
- unless @query
- @query = AgileQuery.new(:name => "_", :project => @project)
- @query.build_from_params(params)
- else
- @query.project = @project if @project
- end
- save_query_attribures_to_session(@query)
- else
- # retrieve from session
- @query = nil
- if session[:agile_query] && !session[:agile_query][:id] && !params[:project_id]
- @query = AgileQuery.new(get_query_attributes_from_session)
- end
-
- @query ||= AgileQuery.find_by_id(session[:agile_query][:id]) if session[:agile_query][:id]
- @query ||= AgileQuery.new(get_query_attributes_from_session)
- @query.project = @project
- save_query_attribures_to_session(@query)
- end
- end
-
- def options_card_colors_for_select(selected, options={})
- color_base = [[l(:label_agile_color_no_colors), "none"],
- [l(:label_issue), "issue"],
- [l(:label_tracker), "tracker"],
- [l(:field_priority), "priority"],
- [l(:label_spent_time), "spent_time"],
- [l(:field_assigned_to), "user"]]
- color_base << [l(:field_project), 'project'] if (@project && @project.children.any?) || !@project
- options_for_select(color_base.compact, selected)
- end
-
- def options_charts_for_select(selected)
- container = []
- RedmineAgile::Charts::AGILE_CHARTS.each { |k, v| container << [l(v[:name]), k] }
- selected_chart = RedmineAgile::Charts.chart_by_alias(selected) || selected
- options_for_select(container, selected_chart)
- end
-
- def grouped_options_charts_for_select(selected)
- grouped_options = {}
- container = []
-
- RedmineAgile::Charts::AGILE_CHARTS.each do |chart, value|
- if RedmineAgile::Charts::CHARTS_WITH_UNITS.include?(chart)
- group = l(value[:name])
- grouped_options[group] = []
- value[:aliases].each do |alias_name|
- grouped_options[group] << ["#{group} (#{l(RedmineAgile::Charts.chart_unit_label_by(alias_name))})", alias_name]
+ def retrieve_agile_query_from_session
+ if session[:agile_query]
+ if session[:agile_query][:id]
+ @query = AgileQuery.find_by_id(session[:agile_query][:id])
+ return unless @query
+ else
+ @query = AgileQuery.new(get_query_attributes_from_session)
end
+ if session[:agile_query].has_key?(:project_id)
+ @query.project_id = session[:agile_query][:project_id]
+ else
+ @query.project = @project
+ end
+ @query
else
- container << [l(value[:name]), chart]
+ @query = AgileQuery.new(:name => "_")
end
end
- grouped_options_for_select(grouped_options, selected) + options_for_select(container, selected)
- end
+ def retrieve_agile_query
+ if !params[:query_id].blank?
+ cond = "project_id IS NULL"
+ cond << " OR project_id = #{@project.id}" if @project
+ @query = AgileQuery.where(cond).find(params[:query_id])
+ raise ::Unauthorized unless @query.visible?
+ @query.project = @project
+ session[:agile_query] = {:id => @query.id, :project_id => @query.project_id}
+ sort_clear
+ elsif api_request? || params[:set_filter] || session[:agile_query].nil? || session[:agile_query][:project_id] != (@project ? @project.id : nil)
+ unless @query
+ @query = AgileQuery.new(:name => "_", :project => @project)
+ @query.build_from_params(params)
+ else
+ @query.project = @project if @project
+ end
+ save_query_attribures_to_session(@query)
+ else
+ # retrieve from session
+ @query = nil
+ if session[:agile_query] && !session[:agile_query][:id] && !params[:project_id]
+ @query = AgileQuery.new(get_query_attributes_from_session)
+ end
- def options_chart_units_for_select(selected = nil)
- container = []
- RedmineAgile::Charts::CHART_UNITS.each { |k, v| container << [l(v), k] }
- selected_unit = RedmineAgile::Charts::CHART_UNIT_BY_ALIAS[selected] || selected
- options_for_select(container, selected_unit)
- end
+ @query ||= AgileQuery.find_by_id(session[:agile_query][:id]) if session[:agile_query][:id]
+ @query ||= AgileQuery.new(get_query_attributes_from_session)
+ @query.project = @project
+ save_query_attribures_to_session(@query)
+ end
+ end
- def render_agile_chart(chart_name, issues_scope)
- render partial: "agile_charts/chart",
- locals: { chart: chart_name, issues_scope: issues_scope, chart_unit: params[:chart_unit] }
- end
+ def options_card_colors_for_select(selected, options={})
+ color_base = [[l(:label_agile_color_no_colors), "none"],
+ [l(:label_issue), "issue"],
+ [l(:label_tracker), "tracker"],
+ [l(:field_priority), "priority"],
+ [l(:label_spent_time), "spent_time"],
+ [l(:field_assigned_to), "user"]]
+ color_base << [l(:field_project), 'project'] if (@project && @project.children.any?) || !@project
+ options_for_select(color_base.compact, selected)
+ end
- def upgrade_to_pro_agile_chart_link(chart_name, query = @query, current_chart = @chart)
- link_to l("label_agile_charts_#{chart_name}"), '#',
- onclick: "showModal('upgrade-to-pro', '557px');",
- class: ('selected' if query.is_a?(AgileChartsQuery) && query.new_record? && current_chart == chart_name)
- end
+ def options_charts_for_select(selected)
+ container = []
+ RedmineAgile::Charts::Helper::AGILE_CHARTS.each { |k, v| container << [l(v[:name]), k] }
+ selected_chart = RedmineAgile::Charts::Helper.chart_by_alias(selected) || selected
+ options_for_select(container, selected_chart)
+ end
- private
+ def grouped_options_charts_for_select(selected)
+ grouped_options = {}
+ container = []
- def get_query_attributes_from_session
- attributes = { name: '_',
- filters: session[:agile_query][:filters],
- group_by: session[:agile_query][:group_by],
- column_names: session[:agile_query][:column_names],
- color_base: session[:agile_query][:color_base] }
- (attributes[:options] = session[:agile_query][:options] || {}) if Redmine::VERSION.to_s > '2.4'
- attributes
- end
+ RedmineAgile::Charts::Helper::AGILE_CHARTS.each do |chart, value|
+ if RedmineAgile::Charts::Helper::CHARTS_WITH_UNITS.include?(chart)
+ group = l(value[:name])
+ grouped_options[group] = []
+ value[:aliases].each do |alias_name|
+ grouped_options[group] << ["#{group} (#{l(RedmineAgile::Charts::Helper.chart_unit_label_by(alias_name))})", alias_name]
+ end
+ else
+ container << [l(value[:name]), chart]
+ end
+ end
- def save_query_attribures_to_session(query)
- session[:agile_query] = { project_id: query.project_id,
- filters: query.filters,
- group_by: query.group_by,
- color_base: (query.respond_to?(:color_base) && query.color_base),
- column_names: query.column_names }
- (session[:agile_query][:options] = query.options) if Redmine::VERSION.to_s > '2.4'
+ grouped_options_for_select(grouped_options, selected) + options_for_select(container, selected)
+ end
+
+ def options_chart_units_for_select(selected = nil)
+ container = []
+ RedmineAgile::Charts::Helper::CHART_UNITS.each { |k, v| container << [l(v), k] }
+ selected_unit = RedmineAgile::Charts::Helper::CHART_UNIT_BY_ALIAS[selected] || selected
+ options_for_select(container, selected_unit)
+ end
+
+ def render_agile_chart(chart_name, issues_scope)
+ render partial: "agile_charts/chart",
+ locals: { chart: chart_name, issues_scope: issues_scope, chart_unit: params[:chart_unit] }
+ end
+
+ def upgrade_to_pro_agile_chart_link(chart_name, query = @query, current_chart = @chart)
+ link_to l("label_agile_charts_#{chart_name}"), '#',
+ onclick: "showModal('upgrade-to-pro', '557px');",
+ class: ('selected' if query.is_a?(AgileChartsQuery) && query.new_record? && current_chart == chart_name)
+ end
+
+ private
+
+ def get_query_attributes_from_session
+ attributes = { name: '_',
+ filters: session[:agile_query][:filters],
+ group_by: session[:agile_query][:group_by],
+ column_names: session[:agile_query][:column_names],
+ color_base: session[:agile_query][:color_base] }
+ (attributes[:options] = session[:agile_query][:options] || {}) if Redmine::VERSION.to_s > '2.4'
+ attributes
+ end
+
+ def save_query_attribures_to_session(query)
+ session[:agile_query] = { project_id: query.project_id,
+ filters: query.filters,
+ group_by: query.group_by,
+ color_base: (query.respond_to?(:color_base) && query.color_base),
+ column_names: query.column_names }
+ (session[:agile_query][:options] = query.options) if Redmine::VERSION.to_s > '2.4'
+ end
end
end
end
-ActionView::Base.send :include, RedmineAgile::AgileHelper
+ActionView::Base.send :include, RedmineAgile::Helpers::AgileHelper
diff --git a/lib/redmine_agile/hooks/controller_issue_hook.rb b/lib/redmine_agile/hooks/controller_issue_hook.rb
index 06cc964..769949d 100644
--- a/lib/redmine_agile/hooks/controller_issue_hook.rb
+++ b/lib/redmine_agile/hooks/controller_issue_hook.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/lib/redmine_agile/hooks/views_issues_hook.rb b/lib/redmine_agile/hooks/views_issues_hook.rb
index d4d7ab2..79154f4 100755
--- a/lib/redmine_agile/hooks/views_issues_hook.rb
+++ b/lib/redmine_agile/hooks/views_issues_hook.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/lib/redmine_agile/hooks/views_layouts_hook.rb b/lib/redmine_agile/hooks/views_layouts_hook.rb
index ef723bc..42eef3f 100644
--- a/lib/redmine_agile/hooks/views_layouts_hook.rb
+++ b/lib/redmine_agile/hooks/views_layouts_hook.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/lib/redmine_agile/hooks/views_versions_hook.rb b/lib/redmine_agile/hooks/views_versions_hook.rb
index 67af1e1..1fc662d 100644
--- a/lib/redmine_agile/hooks/views_versions_hook.rb
+++ b/lib/redmine_agile/hooks/views_versions_hook.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/lib/redmine_agile/patches/issue_drop_patch.rb b/lib/redmine_agile/patches/issue_drop_patch.rb
index db476e5..f152d84 100644
--- a/lib/redmine_agile/patches/issue_drop_patch.rb
+++ b/lib/redmine_agile/patches/issue_drop_patch.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/lib/redmine_agile/patches/issue_patch.rb b/lib/redmine_agile/patches/issue_patch.rb
index 8caca54..60c1395 100755
--- a/lib/redmine_agile/patches/issue_patch.rb
+++ b/lib/redmine_agile/patches/issue_patch.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
@@ -17,9 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with redmine_agile. If not, see .
-require_dependency 'issue'
-require_dependency 'agile_data'
-
module RedmineAgile
module Patches
diff --git a/lib/redmine_agile/patches/issues_controller_patch.rb b/lib/redmine_agile/patches/issues_controller_patch.rb
index 5e4d94c..63a6dd6 100644
--- a/lib/redmine_agile/patches/issues_controller_patch.rb
+++ b/lib/redmine_agile/patches/issues_controller_patch.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/lib/redmine_agile/patches/project_patch.rb b/lib/redmine_agile/patches/project_patch.rb
index 2f4a628..7665c3d 100644
--- a/lib/redmine_agile/patches/project_patch.rb
+++ b/lib/redmine_agile/patches/project_patch.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/lib/redmine_agile/patches/projects_helper_patch.rb b/lib/redmine_agile/patches/projects_helper_patch.rb
index 653c009..d1d0e33 100644
--- a/lib/redmine_agile/patches/projects_helper_patch.rb
+++ b/lib/redmine_agile/patches/projects_helper_patch.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/lib/redmine_agile/patches/queries_controller_patch.rb b/lib/redmine_agile/patches/queries_controller_patch.rb
index 085b7d6..4f8c08c 100644
--- a/lib/redmine_agile/patches/queries_controller_patch.rb
+++ b/lib/redmine_agile/patches/queries_controller_patch.rb
@@ -1,7 +1,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/test/functional/agile_boards_controller_test.rb b/test/functional/agile_boards_controller_test.rb
index 6619a26..700f513 100755
--- a/test/functional/agile_boards_controller_test.rb
+++ b/test/functional/agile_boards_controller_test.rb
@@ -3,7 +3,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/test/functional/agile_charts_controller_test.rb b/test/functional/agile_charts_controller_test.rb
index 0752633..47a903b 100644
--- a/test/functional/agile_charts_controller_test.rb
+++ b/test/functional/agile_charts_controller_test.rb
@@ -3,7 +3,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
@@ -53,8 +53,8 @@ class AgileChartsControllerTest < ActionController::TestCase
EnabledModule.create(project: @project, name: 'agile')
- @charts = RedmineAgile::Charts::AGILE_CHARTS.keys
- @charts_with_units = RedmineAgile::Charts::CHARTS_WITH_UNITS
+ @charts = RedmineAgile::Charts::Helper::AGILE_CHARTS.keys
+ @charts_with_units = RedmineAgile::Charts::Helper::CHARTS_WITH_UNITS
end
def test_get_show
@@ -73,7 +73,7 @@ class AgileChartsControllerTest < ActionController::TestCase
def test_charts_with_chart_unit
@charts_with_units.each do |chart|
- RedmineAgile::Charts::CHART_UNITS.each do |chart_unit, label|
+ RedmineAgile::Charts::Helper::CHART_UNITS.each do |chart_unit, label|
check_chart chart: chart, project_id: @project.identifier, chart_unit: chart_unit
end
end
@@ -81,7 +81,7 @@ class AgileChartsControllerTest < ActionController::TestCase
def test_charts_by_different_time_intervals
@charts.each do |chart|
- RedmineAgile::AgileChart::TIME_INTERVALS.each do |interval|
+ RedmineAgile::Charts::AgileChart::TIME_INTERVALS.each do |interval|
check_chart chart: chart, project_id: @project.identifier, interval_size: interval
end
end
@@ -89,7 +89,7 @@ class AgileChartsControllerTest < ActionController::TestCase
def test_charts_by_different_periods_and_time_intervals
@charts.each do |chart|
- RedmineAgile::AgileChart::TIME_INTERVALS.each do |interval|
+ RedmineAgile::Charts::AgileChart::TIME_INTERVALS.each do |interval|
params = {
chart: chart,
project_id: @project.identifier,
@@ -135,7 +135,7 @@ class AgileChartsControllerTest < ActionController::TestCase
def test_charts_with_version_and_chart_unit
@charts_with_units.each do |chart|
- RedmineAgile::Charts::CHART_UNITS.each do |chart_unit, label|
+ RedmineAgile::Charts::Helper::CHART_UNITS.each do |chart_unit, label|
should_get_render_chart chart: chart, version_id: 2, chart_unit: chart_unit
end
end
@@ -152,7 +152,7 @@ class AgileChartsControllerTest < ActionController::TestCase
)
new_version.fixed_issues << issue.reload
- should_get_render_chart chart: RedmineAgile::Charts::BURNDOWN_CHART, project_id: @project.identifier, version_id: new_version.id
+ should_get_render_chart chart: RedmineAgile::Charts::Helper::BURNDOWN_CHART, project_id: @project.identifier, version_id: new_version.id
end
def test_get_show_chart_with_open_target_version
diff --git a/test/functional/agile_journal_details_controller_test.rb b/test/functional/agile_journal_details_controller_test.rb
index 5d3db81..98d86c7 100644
--- a/test/functional/agile_journal_details_controller_test.rb
+++ b/test/functional/agile_journal_details_controller_test.rb
@@ -3,7 +3,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/test/functional/issues_controller_test.rb b/test/functional/issues_controller_test.rb
index f124644..c81e632 100644
--- a/test/functional/issues_controller_test.rb
+++ b/test/functional/issues_controller_test.rb
@@ -3,7 +3,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/test/functional/projects_controller_test.rb b/test/functional/projects_controller_test.rb
index 67d3a32..3a68eb2 100644
--- a/test/functional/projects_controller_test.rb
+++ b/test/functional/projects_controller_test.rb
@@ -3,7 +3,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/test/functional/users_controller_test.rb b/test/functional/users_controller_test.rb
index 71aa90c..0fd206e 100644
--- a/test/functional/users_controller_test.rb
+++ b/test/functional/users_controller_test.rb
@@ -3,7 +3,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/test/integration/api_test/agile_data_test.rb b/test/integration/api_test/agile_data_test.rb
index bae9bcd..4656ab7 100644
--- a/test/integration/api_test/agile_data_test.rb
+++ b/test/integration/api_test/agile_data_test.rb
@@ -3,7 +3,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/test/integration/common_views_test.rb b/test/integration/common_views_test.rb
index eb3936c..83f7004 100644
--- a/test/integration/common_views_test.rb
+++ b/test/integration/common_views_test.rb
@@ -3,7 +3,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/test/test_helper.rb b/test/test_helper.rb
index 1c345e1..69b348b 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -3,7 +3,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/test/ui/agile_board_ui_test.rb b/test/ui/agile_board_ui_test.rb
index b27389f..e71b77d 100644
--- a/test/ui/agile_board_ui_test.rb
+++ b/test/ui/agile_board_ui_test.rb
@@ -3,7 +3,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/test/unit/agile_charts_query_test.rb b/test/unit/agile_charts_query_test.rb
index a9fde49..d2827a3 100644
--- a/test/unit/agile_charts_query_test.rb
+++ b/test/unit/agile_charts_query_test.rb
@@ -3,7 +3,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/test/unit/agile_data_test.rb b/test/unit/agile_data_test.rb
index 13bf20a..01f4fc9 100644
--- a/test/unit/agile_data_test.rb
+++ b/test/unit/agile_data_test.rb
@@ -3,7 +3,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
diff --git a/test/unit/charts/burndown_chart_test.rb b/test/unit/charts/burndown_chart_test.rb
index e051a10..5fd3960 100644
--- a/test/unit/charts/burndown_chart_test.rb
+++ b/test/unit/charts/burndown_chart_test.rb
@@ -3,7 +3,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify
@@ -38,7 +38,7 @@ class BurndownChartTest < ActiveSupport::TestCase
test_case_issues = test_case[:issues].call
test_case[:inerval_data].each do |case_interval|
puts "BurndownChartTest case - #{case_interval[:name]}"
- chart_data = RedmineAgile::BurndownChart.data(test_case_issues, case_interval[:options])
+ chart_data = RedmineAgile::Charts::BurndownChart.data(test_case_issues, case_interval[:options])
assert_equal case_interval[:result], extract_values(chart_data)
end
test_case_issues.destroy_all
diff --git a/test/unit/helpers/agile_boards_helper_test.rb b/test/unit/helpers/agile_boards_helper_test.rb
index accb368..e6595b8 100644
--- a/test/unit/helpers/agile_boards_helper_test.rb
+++ b/test/unit/helpers/agile_boards_helper_test.rb
@@ -3,7 +3,7 @@
# This file is a part of Redmin Agile (redmine_agile) plugin,
# Agile board plugin for redmine
#
-# Copyright (C) 2011-2021 RedmineUP
+# Copyright (C) 2011-2022 RedmineUP
# http://www.redmineup.com/
#
# redmine_agile is free software: you can redistribute it and/or modify