├── .DS_Store
├── README.rdoc
├── app
├── controllers
│ └── parking_lot_chart_controller.rb
├── helpers
│ └── parking_lot_chart_helper.rb
└── views
│ └── parking_lot_chart
│ └── index.html.erb
├── config
├── .DS_Store
├── locales
│ ├── de.yml
│ ├── en.yml
│ ├── ja.yml
│ └── ko.yml
└── routes.rb
├── init.rb
├── lang
├── en.yml
└── ja.yml
├── lib
└── parking_lot_chart_data.rb
└── test
├── functional
└── parking_lot_chart_controller_test.rb
└── test_helper.rb
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daipresents/redmine_parking_lot_chart/4096b34b308b44a9798ef764707e9114f8ccbeb5/.DS_Store
--------------------------------------------------------------------------------
/README.rdoc:
--------------------------------------------------------------------------------
1 | = redmine_parking_lot_chart
2 | アジャイルな見積りと計画づくりに登場する、テーマやストーリーの完了状況を可視化したツールをRedmineにそそぎこむ。
3 | (Parking lot chart appears in the Agile estimating and planning. This chart makes the theme and the story visible. I try to create redmine plugin for agile development tool.)
4 |
5 | ロードマップという機能が存在するが、縦に長いページだと状況がわかりずらい。モバイルページと同じく、1画面でできるだけ多くの情報をわかりやすく表示するためにプラグインを作ってみる。
6 | (Redmine Roadmap is wonderful feature. but if threre are a lot of version, roadmap page is became very long page. So parking lot chart plugin offers the feature to display a lot of information on one screen.)
7 |
8 | 作者は英語が得意ではありません。
9 | (The author is not good at English.Sorry..)
10 |
11 | == Details
12 | - プロジェクト内のバージョンをカード形式で表示します。(The version in the project is displayed by the card format.)
13 |
14 | == Plugin Installation for Rails.version >= '3.0'
15 | - Download this plugin.
16 | - Unpack and move into RAILS_ROOT/plugins.
17 | - Restart Redmine.
18 | - Login and configure the plugin (Administration > Roles and permissions > Permissions report)
19 | - Configure the project (Project > Settings > Modules).
20 | - Click to Parking Lot Chart menu.
21 |
22 | == Plugin Installation for Rails.version < '3.0'
23 | - Download this plugin.
24 | - Unpack and move into RAILS_ROOT/vendor/plugins.
25 | - Rename the plugin directory to parking_lot_chart
26 | - Restart Redmine.
27 | - Login and configure the plugin (Administration > Roles and permissions > Permissions report)
28 | - Configure the project (Project > Settings > Modules).
29 | - Click to Parking Lot Chart menu.
30 |
31 |
32 | == Note
33 | - This plugin works only Redmine 0.9.0 or higher.
34 |
35 | == License
36 | This plugin is licensed under GNU General Public License version 3.
37 |
38 |
--------------------------------------------------------------------------------
/app/controllers/parking_lot_chart_controller.rb:
--------------------------------------------------------------------------------
1 | require 'parking_lot_chart_data'
2 |
3 | class ParkingLotChartController < ApplicationController
4 | unloadable
5 | menu_item :parking_lot_chart
6 | before_filter :find_project, :find_issues_open_status, :find_all_versions
7 |
8 | DEBUG = false
9 |
10 | def index
11 | if DEBUG
12 | @today = Date::new(2010, 3, 8)
13 | else
14 | @today = Date.today
15 | end
16 | versions = find_versions
17 | @chart_data = []
18 | versions.each do |version|
19 | data = ParkingLotChartData.new
20 | data.id = version.id
21 | data.name = version.name
22 | if version.estimated_hours
23 | data.estimated_hours = round(version.estimated_hours)
24 | else
25 | data.estimated_hours = 0
26 | end
27 | data.open_issues_count = version.open_issues_count
28 | data.closed_issues_count = version.closed_issues_count
29 | data.effective_date = version.effective_date
30 | data.status = version.status
31 | if version.effective_date
32 | if data.open_issues_count == 0 && 0 < data.closed_issues_count
33 | data.issues_status = "closed"
34 | elsif version.effective_date < @today
35 | data.issues_status = "late"
36 | elsif version.effective_date <= (@today + 2)
37 | data.issues_status = "pinch"
38 | elsif (data.effective_date - 6) <= @today
39 | data.issues_status = "one more week"
40 | else
41 | data.issues_status = "relax"
42 | end
43 | else
44 | data.issues_status = "late"
45 | end
46 | data.open_issues_pourcent = calc_open_issues_pourcent(version.id, version.estimated_hours)
47 | data.closed_issues_pourcent = 100 - data.open_issues_pourcent
48 | @chart_data.push(data)
49 | end
50 | end
51 |
52 | def calc_open_issues_pourcent(version_id, total_hours)
53 | sum = 0
54 | @open_statuses.each do |status|
55 | sum += Issue.sum(:estimated_hours, :conditions => {:fixed_version_id => version_id, :status_id => status.id})
56 | end
57 |
58 | if sum == 0
59 | return 0
60 | else
61 | return round(sum / total_hours * 100)
62 | end
63 | end
64 |
65 | def round(value)
66 | if value.nil? || value == 0
67 | return 0
68 | else
69 | return ((value * 10.0).round / 10.0).to_f
70 | end
71 | end
72 |
73 | def find_versions
74 | unless params[:status]
75 | return find_open_versions
76 | else
77 | if params[:status] == "closed"
78 | return find_closed_versions
79 | elsif params[:status] == "locked"
80 | return find_locked_versions
81 | elsif params[:status] == "no_effective_date"
82 | return find_no_effectvie_date_versions
83 | elsif params[:status] == "all"
84 | return @versions
85 | else
86 | return find_open_versions
87 | end
88 | end
89 | end
90 |
91 | def find_open_versions
92 | return @versions.select{|version| version.status == "open"}
93 | end
94 |
95 | def find_closed_versions
96 | return @versions.select{|version| version.status == "closed"}
97 | end
98 |
99 | def find_locked_versions
100 | return @versions.select{|version| version.status == "locked"}
101 | end
102 |
103 | def find_no_effectvie_date_versions
104 | return @project.versions.select{|version| !version.effective_date}
105 | end
106 |
107 | def find_all_versions
108 | @versions = @project.versions.select(&:effective_date).sort_by(&:effective_date)
109 | end
110 |
111 | private
112 | def find_project
113 | render_error(l(:parking_lot_chart_project_not_found, :project_id => 'parameter not found.')) and return unless params[:project_id]
114 | begin
115 | @project = Project.find(params[:project_id])
116 | rescue ActiveRecord::NotFound
117 | render_error(l(:parking_lot_chart_project_not_found, :project_id => params[:project_id])) and return unless @project
118 | end
119 | end
120 |
121 | private
122 | def find_issues_open_status
123 | @open_statuses = IssueStatus.find_all_by_is_closed(false)
124 | end
125 | end
126 |
--------------------------------------------------------------------------------
/app/helpers/parking_lot_chart_helper.rb:
--------------------------------------------------------------------------------
1 | module ParkingLotChartHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/views/parking_lot_chart/index.html.erb:
--------------------------------------------------------------------------------
1 | <% html_title "#{@project.name} - " + l(:parking_lot_chart) -%>
2 |
3 | <% content_for :header_tags do %>
4 |
17 | <% end %>
18 |
19 | <% content_for :sidebar do -%>
20 |
<%= l(:parking_lot_chart_menu_info) %>
21 | <%= l(:parking_lot_chart_menu_today, :today => @today) %>
22 |
23 |
<%= l(:parking_lot_chart_menu_color_late) %>
24 |
<%= l(:parking_lot_chart_menu_color_pinch) %>
25 |
<%= l(:parking_lot_chart_menu_color_1week) %>
26 |
<%= l(:parking_lot_chart_menu_color_relax) %>
27 |
<%= l(:parking_lot_chart_menu_color_closed) %>
28 |
29 | <%= l(:parking_lot_chart_menu_filter) %>
30 | <%= " style='font-weight:bold'" %><% end %>>
31 | <%= link_to l(:parking_lot_chart_open_version), {:controller => 'parking_lot_chart', :action => 'index', :project_id => @project.identifier} %>
32 |
33 | <%= " style='font-weight:bold'" %><% end %>>
34 | <%= link_to l(:parking_lot_chart_locked_version), {:controller => 'parking_lot_chart', :action => 'index', :project_id => @project.identifier, :status => 'locked'} %>
35 |
36 | <%= " style='font-weight:bold'" %><% end %>>
37 | <%= link_to l(:parking_lot_chart_closed_version), {:controller => 'parking_lot_chart', :action => 'index', :project_id => @project.identifier, :status => 'closed'} %>
38 |
39 |
40 | <%= " style='font-weight:bold'" %><% end %>>
41 | <%= link_to l(:parking_lot_chart_all_version), {:controller => 'parking_lot_chart', :action => 'index', :project_id => @project.identifier, :status => 'all'} %>
42 |
43 | <%= " style='font-weight:bold'" %><% end %>>
44 | <%= link_to l(:parking_lot_chart_no_effective_date_version), {:controller => 'parking_lot_chart', :action => 'index', :project_id => @project.identifier, :status => 'no_effective_date'} %>
45 |
46 | <% end -%>
47 |
48 | <% @chart_data.each do |data| %>
49 | <%
50 | if data.issues_status == 'closed'
51 | style = "background-color:#cccccc;"
52 | elsif data.issues_status == 'late'
53 | style = "background-color:#ff6666;"
54 | elsif data.issues_status == 'pinch'
55 | style = "background-color:#ff9900;"
56 | elsif data.issues_status == 'one more week'
57 | style = "background-color:#ffff66;"
58 | elsif data.issues_status == 'relax'
59 | style = "background-color:#ccffff;"
60 | else
61 | style = "background-color:#ccffff;"
62 | end
63 | %>
64 |
65 |
66 | <%= link_to data.name, {:controller => 'versions', :action => 'show', :id => data.id} %>
67 |
68 |
69 | <%= l(:parking_lot_chart_estimated_hours) %>:<%= data.estimated_hours %>
70 | <%= link_to l(:parking_lot_chart_closed) + data.closed_issues_count.to_s, {:controller => 'issues', :action => 'index', :project_id => @project.identifier, :fixed_version_id => data.id, :set_filter => 1, :status_id => "c"} %>
71 | /
72 | <%= link_to l(:parking_lot_chart_open) + data.open_issues_count.to_s, {:controller => 'issues', :action => 'index', :project_id => @project.identifier, :fixed_version_id => data.id, :set_filter => 1, :status_id => "o"} %>
73 | <%= l(:parking_lot_chart_effective_date) %>:<% if data.effective_date %><%= data.effective_date %><% else %>---<% end %>
74 |
75 |
76 |
77 |
78 | <% if data.closed_issues_count == 0 || data.open_issues_count + data.closed_issues_count == 0 %>
79 | |
80 | <% elsif data.closed_issues_count >= 1 && data.open_issues_count == 0 %>
81 | |
82 | <% else %>
83 | |
84 | |
85 | <% end %>
86 |
87 |
88 |
89 |
90 | <% end %>
91 |
92 |
93 |
--------------------------------------------------------------------------------
/config/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daipresents/redmine_parking_lot_chart/4096b34b308b44a9798ef764707e9114f8ccbeb5/config/.DS_Store
--------------------------------------------------------------------------------
/config/locales/de.yml:
--------------------------------------------------------------------------------
1 | de:
2 | parking_lot_chart: "Parkplatz Diagramm"
3 | parking_lot_chart_closed: "Geschlossen"
4 | parking_lot_chart_open: "Offen"
5 | parking_lot_chart_estimated_hours: "Geschätzte Dauer"
6 | parking_lot_chart_effective_date: "Stichtag"
7 |
8 | parking_lot_chart_menu_info: "Information"
9 | parking_lot_chart_menu_filter: "Filter"
10 | parking_lot_chart_menu_today: "Heute: %{today}"
11 | parking_lot_chart_menu_color_late: "In Verzug"
12 | parking_lot_chart_menu_color_pinch: "Verzögert"
13 | parking_lot_chart_menu_color_1week: "Nächste Woche"
14 | parking_lot_chart_menu_color_relax: "Alles In Ordnung"
15 | parking_lot_chart_menu_color_closed: "Geschlossen"
16 |
17 | parking_lot_chart_all_version: "Alle Versionen"
18 | parking_lot_chart_open_version: "Sprint Versionen"
19 | parking_lot_chart_locked_version: "Gesperrte Versionen"
20 | parking_lot_chart_closed_version: "Abgeschlossene Versionen"
21 | parking_lot_chart_no_effective_date_version: "Ohne Stichtag"
22 |
23 | parking_lot_chart_project_not_found: "Projekt nicht gefunden. project_id:%{project_id}"
24 |
--------------------------------------------------------------------------------
/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | en:
2 | parking_lot_chart: "Parking Lot Chart"
3 | parking_lot_chart_closed: "Closed"
4 | parking_lot_chart_open: "Open"
5 | parking_lot_chart_estimated_hours: "Estimated Hours"
6 | parking_lot_chart_effective_date: "Effective Date"
7 |
8 | parking_lot_chart_menu_info: "Information"
9 | parking_lot_chart_menu_filter: "Filter"
10 | parking_lot_chart_menu_today: "Today:%{today}"
11 | parking_lot_chart_menu_color_late: "Delay"
12 | parking_lot_chart_menu_color_pinch: "Pinch"
13 | parking_lot_chart_menu_color_1week: "Another week"
14 | parking_lot_chart_menu_color_relax: "Everything OK?"
15 | parking_lot_chart_menu_color_closed: "Closed"
16 |
17 | parking_lot_chart_all_version: "All Version"
18 | parking_lot_chart_open_version: "Sprint Version"
19 | parking_lot_chart_locked_version: "Locked Version"
20 | parking_lot_chart_closed_version: "Closed Version"
21 | parking_lot_chart_no_effective_date_version: "No Effective Date"
22 |
23 | parking_lot_chart_project_not_found: "Project not found. project_id:%{project_id}"
24 |
--------------------------------------------------------------------------------
/config/locales/ja.yml:
--------------------------------------------------------------------------------
1 | ja:
2 | parking_lot_chart: "パーキングロットチャート"
3 | parking_lot_chart_closed: "完了"
4 | parking_lot_chart_open: "未完了"
5 | parking_lot_chart_estimated_hours: "予定工数"
6 | parking_lot_chart_effective_date: "期日"
7 |
8 | parking_lot_chart_menu_info: "Information"
9 | parking_lot_chart_menu_filter: "フィルタ"
10 | parking_lot_chart_menu_today: "今日は%{today}です。"
11 | parking_lot_chart_menu_color_late: "遅延発生"
12 | parking_lot_chart_menu_color_pinch: "ピンチ"
13 | parking_lot_chart_menu_color_1week: "残り1週間を切りました"
14 | parking_lot_chart_menu_color_relax: "残り1週間以上です"
15 | parking_lot_chart_menu_color_closed: "完了"
16 |
17 | parking_lot_chart_all_version: "すべてのバージョン"
18 | parking_lot_chart_open_version: "スプリント中のバージョン"
19 | parking_lot_chart_locked_version: "ロック中のバージョン"
20 | parking_lot_chart_closed_version: "完了したバージョン"
21 | parking_lot_chart_no_effective_date_version: "期限のないバージョン"
22 |
23 | parking_lot_chart_project_not_found: "プロジェクトが存在しません。プロジェクトID:%{project_id}"
24 |
25 |
--------------------------------------------------------------------------------
/config/locales/ko.yml:
--------------------------------------------------------------------------------
1 | # Translation by Ki Won Kim (http://xyz37.blog.me, xyz37@naver.com)
2 | ko:
3 | parking_lot_chart: "격자 차트"
4 | parking_lot_chart_closed: "완료됨"
5 | parking_lot_chart_open: "진행"
6 | parking_lot_chart_estimated_hours: "평가 시간"
7 | parking_lot_chart_effective_date: "유효 일자"
8 |
9 | parking_lot_chart_menu_info: "정보"
10 | parking_lot_chart_menu_filter: "필터"
11 | parking_lot_chart_menu_today: "오늘:%{today}"
12 | parking_lot_chart_menu_color_late: "지연됨"
13 | parking_lot_chart_menu_color_pinch: "막바지"
14 | parking_lot_chart_menu_color_1week: "다른 주(week)"
15 | parking_lot_chart_menu_color_relax: "모두 정상?"
16 | parking_lot_chart_menu_color_closed: "완료됨"
17 |
18 | parking_lot_chart_all_version: "모든 버전"
19 | parking_lot_chart_open_version: "진행중인 버전"
20 | parking_lot_chart_locked_version: "잠긴 버전"
21 | parking_lot_chart_closed_version: "완료된 버전"
22 | parking_lot_chart_no_effective_date_version: "유효 일자 없음"
23 |
24 | parking_lot_chart_project_not_found: "프로젝트가 없습니다. 프로젝트 식별자:%{project_id}"
25 |
--------------------------------------------------------------------------------
/config/routes.rb:
--------------------------------------------------------------------------------
1 | if Rails.version < '3.0'
2 | ActionController::Routing::Routes.draw do |map|
3 | map.connect 'parking_lot_chart/:action', :controller => 'parking_lot_chart'
4 | end
5 | else # Rails 3
6 | RedmineApp::Application.routes.draw do
7 | match 'parking_lot_chart/:action', :controller => 'parking_lot_chart'
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/init.rb:
--------------------------------------------------------------------------------
1 | require 'redmine'
2 |
3 | Redmine::Plugin.register :redmine_parking_lot_chart do
4 | name 'Redmine Parking Lot Chart plugin'
5 | author 'Dai Fujihara'
6 | description 'Parking lot chart appears in the Agile estimating and planning. This chart makes the theme and the story visible. I try to create redmine plugin for agile development tool.'
7 | author_url 'http://daipresents.com/'
8 | url 'http://daipresents.com/2010/redmine_parking_lot_chart_plugin/'
9 |
10 | requires_redmine :version_or_higher => '1.1.3'
11 | version '0.0.7'
12 |
13 | project_module :parking_lot_chart do
14 | permission :parking_lot_chart_view, :parking_lot_chart => :index
15 | end
16 |
17 | menu :project_menu, :parking_lot_chart, { :controller => 'parking_lot_chart', :action => 'index' },
18 | :caption => :parking_lot_chart, :after => :roadmap, :param => :project_id
19 | end
20 |
--------------------------------------------------------------------------------
/lang/en.yml:
--------------------------------------------------------------------------------
1 | parking_lot_chart: "Parking Lot Chart"
2 | parking_lot_chart_closed: "Closed"
3 | parking_lot_chart_open: "Open"
4 | parking_lot_chart_estimated_hours: "Estimated Hours"
5 | parking_lot_chart_effective_date: "Effective Date"
6 |
7 | parking_lot_chart_menu_info: "Information"
8 | parking_lot_chart_menu_filter: "Filter"
9 | parking_lot_chart_menu_today: "Today:{{today}}"
10 | parking_lot_chart_menu_color_late: "Delay"
11 | parking_lot_chart_menu_color_pinch: "Pinch"
12 | parking_lot_chart_menu_color_1week: "Anothre week"
13 | parking_lot_chart_menu_color_relax: "Everything OK?"
14 | parking_lot_chart_menu_color_closed: "Closed"
15 |
16 | parking_lot_chart_all_version: "All Version"
17 | parking_lot_chart_open_version: "Sprint Version"
18 | parking_lot_chart_locked_version: "Locked Version"
19 | parking_lot_chart_closed_version: "Closed Version"
20 | parking_lot_chart_no_effective_date_version: "No Effective Date"
21 |
22 | parking_lot_chart_project_not_found: "Project not found. project_id:{{project_id}}"
--------------------------------------------------------------------------------
/lang/ja.yml:
--------------------------------------------------------------------------------
1 | parking_lot_chart: "パーキングロットチャート"
2 | parking_lot_chart_closed: "完了"
3 | parking_lot_chart_open: "未完了"
4 | parking_lot_chart_estimated_hours: "予定工数"
5 | parking_lot_chart_effective_date: "期日"
6 |
7 | parking_lot_chart_menu_info: "Information"
8 | parking_lot_chart_menu_filter: "フィルタ"
9 | parking_lot_chart_menu_today: "今日は{{today}}です。"
10 | parking_lot_chart_menu_color_late: "遅延発生"
11 | parking_lot_chart_menu_color_pinch: "ピンチ"
12 | parking_lot_chart_menu_color_1week: "残り1週間を切りました"
13 | parking_lot_chart_menu_color_relax: "残り1週間以上です"
14 | parking_lot_chart_menu_color_closed: "完了"
15 |
16 | parking_lot_chart_all_version: "すべてのバージョン"
17 | parking_lot_chart_open_version: "スプリント中のバージョン"
18 | parking_lot_chart_locked_version: "ロック中のバージョン"
19 | parking_lot_chart_closed_version: "完了したバージョン"
20 | parking_lot_chart_no_effective_date_version: "期限のないバージョン"
21 |
22 | parking_lot_chart_project_not_found: "プロジェクトが存在しません。プロジェクトID:{{project_id}}"
23 |
24 |
--------------------------------------------------------------------------------
/lib/parking_lot_chart_data.rb:
--------------------------------------------------------------------------------
1 | class ParkingLotChartData
2 | def initialize
3 |
4 | end
5 |
6 | attr_accessor :id, :name, :estimated_hours,
7 | :open_issues_count, :closed_issues_count, :effective_date, :status,
8 | :open_issues_pourcent, :closed_issues_pourcent, :issues_status
9 | end
10 |
--------------------------------------------------------------------------------
/test/functional/parking_lot_chart_controller_test.rb:
--------------------------------------------------------------------------------
1 | require File.dirname(__FILE__) + '/../test_helper'
2 |
3 | class ParkingLotChartControllerTest < ActionController::TestCase
4 | # Replace this with your real tests.
5 | def test_truth
6 | assert true
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | # Load the normal Rails helper
2 | require File.expand_path(File.dirname(__FILE__) + '/../../../../test/test_helper')
3 |
4 | # Ensure that we are using the temporary fixture path
5 | Engines::Testing.set_fixture_path
6 |
--------------------------------------------------------------------------------