branston 0.4.5 → 0.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/branston/app/controllers/stories_controller.rb +95 -81
- data/lib/branston/app/helpers/iterations_helper.rb +38 -32
- data/lib/branston/app/models/iteration.rb +4 -4
- data/lib/branston/app/models/story.rb +2 -0
- data/lib/branston/app/views/iterations/show.html.erb +46 -40
- data/lib/branston/public/stylesheets/application.css +2 -0
- metadata +2 -2
@@ -13,44 +13,42 @@
|
|
13
13
|
# along with Branston. If not, see <http://www.gnu.org/licenses/>.
|
14
14
|
|
15
15
|
class StoriesController < ApplicationController
|
16
|
-
|
16
|
+
|
17
17
|
layout 'main'
|
18
18
|
before_filter :login_required, :except => [:show, :generate_feature]
|
19
|
-
before_filter :retrieve_iterations, :except => [:generate_feature]
|
19
|
+
before_filter :retrieve_iterations, :except => [:generate_feature, :show]
|
20
20
|
before_filter :load_iteration, :except => [:generate_feature, :show]
|
21
|
-
|
22
21
|
in_place_edit_for :story, :title
|
23
22
|
in_place_edit_for :story, :description
|
24
23
|
in_place_edit_for :story, :points
|
25
|
-
|
24
|
+
|
26
25
|
def generate_feature
|
27
26
|
@story = Story.find_by_slug(params[:id])
|
28
27
|
if @story.nil?
|
29
|
-
@story = Story.find(:first, :include => :scenarios,
|
30
|
-
:conditions => ['slug LIKE ?', "%#{id}%"] )
|
28
|
+
@story = Story.find(:first, :include => :scenarios, :conditions => ['slug LIKE ?', "%#{id}%"] )
|
31
29
|
end
|
32
30
|
@story.generate(@story)
|
33
31
|
render :text => 'done'
|
34
32
|
end
|
35
|
-
|
33
|
+
|
36
34
|
# GET /stories
|
37
35
|
# GET /stories.xml
|
38
36
|
def index
|
39
37
|
@current_stories = Story.for_iteration(@iteration.id).in_progress
|
40
38
|
@backlog_stories = Story.for_iteration(@iteration.id).unassigned
|
41
39
|
@completed_stories = Story.for_iteration(@iteration.id).completed
|
42
|
-
|
40
|
+
|
43
41
|
respond_to do |format|
|
44
42
|
format.html # index.html.erb
|
45
43
|
format.xml { render :xml => @stories }
|
46
44
|
end
|
47
45
|
end
|
48
|
-
|
46
|
+
|
49
47
|
# GET /stories/1
|
50
48
|
# GET /stories/1.xml
|
51
49
|
def show
|
52
50
|
@story = Story.find_by_slug(params[:id])
|
53
|
-
|
51
|
+
|
54
52
|
respond_to do |format|
|
55
53
|
if @story
|
56
54
|
format.html {
|
@@ -60,86 +58,102 @@ class StoriesController < ApplicationController
|
|
60
58
|
render :xml => (@story.to_xml :include => { :scenarios => {
|
61
59
|
:include => [:preconditions, :outcomes] } } ) }
|
62
60
|
format.js { @active = true }
|
63
|
-
|
64
|
-
format.html {
|
61
|
+
else
|
62
|
+
format.html {
|
63
|
+
@iteration = load_iteration
|
64
|
+
render_optional_error_file 404
|
65
|
+
}
|
65
66
|
format.all { render :nothing => true, :status => 404 }
|
67
|
+
end
|
66
68
|
end
|
67
69
|
end
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
70
|
+
|
71
|
+
# GET /stories/new
|
72
|
+
# GET /stories/new.xml
|
73
|
+
def new
|
74
|
+
@story = Story.new(:iteration => @iteration)
|
75
|
+
|
76
|
+
respond_to do |format|
|
77
|
+
format.html # new.html.erb
|
78
|
+
format.xml { render :xml => @story }
|
79
|
+
end
|
78
80
|
end
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
81
|
+
|
82
|
+
# GET /stories/1/edit
|
83
|
+
def edit
|
84
|
+
@story = Story.find_by_slug(params[:id])
|
85
|
+
end
|
86
|
+
|
87
|
+
# POST /stories
|
88
|
+
# POST /stories.xml
|
89
|
+
def create
|
90
|
+
@story = Story.new(params[:story])
|
91
|
+
@story.author = current_user
|
92
|
+
@story.iteration = @iteration
|
93
|
+
|
94
|
+
respond_to do |format|
|
95
|
+
if @story.save
|
96
|
+
flash[:notice] = 'Story was successfully created.'
|
97
|
+
format.html { redirect_to iteration_stories_path(@iteration) }
|
98
|
+
format.xml { render :xml => @story, :status => :created, :location => @story }
|
99
|
+
else
|
100
|
+
format.html { render :action => "new" }
|
101
|
+
format.xml { render :xml => @story.errors, :status => :unprocessable_entity }
|
102
|
+
end
|
101
103
|
end
|
102
104
|
end
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
105
|
+
|
106
|
+
# PUT /stories/"1
|
107
|
+
# PUT /stories/1.xml
|
108
|
+
def update
|
109
|
+
@story = Story.find_by_slug(params[:id])
|
110
|
+
|
111
|
+
if params[:story] and params[:story][:status]
|
112
|
+
if params[:story][:status] == 'in_progress'
|
113
|
+
@story.assign
|
114
|
+
end
|
115
|
+
|
116
|
+
if params[:story][:status] == 'completed'
|
117
|
+
@story.finish
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
respond_to do |format|
|
122
|
+
if @story.update_attributes(params[:story])
|
123
|
+
flash[:notice] = 'Story was successfully updated.'
|
124
|
+
format.html { redirect_to iteration_story_path(@iteration, @story) }
|
125
|
+
format.xml { head :ok }
|
126
|
+
format.js { redirect_to iteration_stories_path(@iteration) }
|
127
|
+
else
|
128
|
+
format.html { render :action => "edit" }
|
129
|
+
format.xml { render :xml => @story.errors, :status => :unprocessable_entity }
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
# DELETE /stories/1
|
137
|
+
# DELETE /stories/1.xml
|
138
|
+
def destroy
|
139
|
+
@story = Story.find_by_slug(params[:id])
|
140
|
+
@story.destroy
|
141
|
+
|
142
|
+
respond_to do |format|
|
143
|
+
format.html { redirect_to iteration_stories_path(@iteration) }
|
113
144
|
format.xml { head :ok }
|
114
|
-
format.js { redirect_to iteration_stories_path(@iteration) }
|
115
|
-
else
|
116
|
-
format.html { render :action => "edit" }
|
117
|
-
format.xml { render :xml => @story.errors, :status => :unprocessable_entity }
|
118
145
|
end
|
119
146
|
end
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
@story.destroy
|
127
|
-
|
128
|
-
respond_to do |format|
|
129
|
-
format.html { redirect_to iteration_stories_path(@iteration) }
|
130
|
-
format.xml { head :ok }
|
147
|
+
|
148
|
+
|
149
|
+
private
|
150
|
+
|
151
|
+
def retrieve_iterations
|
152
|
+
@iterations = Iteration.all
|
131
153
|
end
|
154
|
+
|
155
|
+
def load_iteration
|
156
|
+
@iteration = Iteration.find(params[:iteration_id])
|
157
|
+
end
|
132
158
|
end
|
133
159
|
|
134
|
-
|
135
|
-
private
|
136
|
-
|
137
|
-
def retrieve_iterations
|
138
|
-
@iterations = Iteration.all
|
139
|
-
end
|
140
|
-
|
141
|
-
def load_iteration
|
142
|
-
@iteration = Iteration.find(params[:iteration_id])
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
@@ -1,40 +1,46 @@
|
|
1
1
|
module IterationsHelper
|
2
|
-
|
2
|
+
|
3
3
|
# TODO: Untested!
|
4
4
|
#
|
5
5
|
def burndown_chart(iteration, data)
|
6
|
-
|
7
|
-
total_points =
|
8
|
-
|
9
|
-
|
6
|
+
|
7
|
+
total_points = iteration.velocity
|
8
|
+
running_total = 0
|
9
|
+
|
10
10
|
unless data.nil? or data.empty?
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
11
|
+
points_data = data.map { |d|
|
12
|
+
running_total += d.points.to_i
|
13
|
+
total_points - running_total
|
14
|
+
}
|
15
|
+
|
16
|
+
|
17
|
+
points_data = [total_points] + points_data unless points_data.nil?
|
18
|
+
|
19
|
+
work_days = [nil]
|
20
|
+
(iteration.start_date.to_date..iteration.end_date.to_date).to_a.each do |date|
|
21
|
+
work_days.push date.strftime('%d/%m') unless date.wday == 0 or date.wday == 6
|
22
|
+
end
|
23
|
+
|
24
|
+
# Keep adding the last value to flatline the chart
|
25
|
+
while work_days.length > points_data.length
|
26
|
+
points_data.push points_data.last
|
27
|
+
end
|
28
|
+
|
29
|
+
# Make some gradations for the y axis labels
|
30
|
+
y_scale = [0]
|
31
|
+
[4, 2, 1.5, 1.25, 1].each do |n|
|
32
|
+
unit = (total_points / n).floor
|
33
|
+
y_scale.push unit if unit > 0
|
34
|
+
end
|
35
|
+
|
36
|
+
image_tag Gchart.line(:size => '800x360',
|
37
|
+
:title => "Iteration #{iteration.name} burndown",
|
38
|
+
:data => points_data, :axis_with_labels => 'x,y',
|
39
|
+
:axis_labels => [work_days, y_scale])
|
40
|
+
|
41
|
+
end
|
42
|
+
|
30
43
|
end
|
31
|
-
|
32
|
-
image_tag Gchart.line(:size => '500x300',
|
33
|
-
:title => "#{iteration.name} burndown",
|
34
|
-
:data => points_data, :axis_with_labels => 'x,y',
|
35
|
-
:axis_labels => [work_days, y_scale])
|
36
|
-
|
44
|
+
|
37
45
|
end
|
38
46
|
|
39
|
-
end
|
40
|
-
|
@@ -28,14 +28,14 @@ class Iteration < ActiveRecord::Base
|
|
28
28
|
belongs_to :release
|
29
29
|
|
30
30
|
def burndown_data
|
31
|
-
|
32
|
-
"SELECT SUM(points) AS
|
33
|
-
COUNT(points) AS points,
|
31
|
+
Story.find_by_sql [
|
32
|
+
"SELECT SUM(points) AS points,
|
34
33
|
completed_date
|
35
34
|
FROM stories
|
36
35
|
WHERE iteration_id = ?
|
37
36
|
AND status = 'completed'
|
38
|
-
GROUP BY completed_date
|
37
|
+
GROUP BY completed_date
|
38
|
+
ORDER bY completed_date", id
|
39
39
|
]
|
40
40
|
end
|
41
41
|
|
@@ -1,44 +1,50 @@
|
|
1
|
-
<div
|
2
|
-
|
3
|
-
<b>Velocity:</b>
|
4
|
-
<%=h @iteration.velocity %>
|
5
|
-
</p>
|
6
|
-
|
7
|
-
<p>
|
8
|
-
<b>Name:</b>
|
9
|
-
<%=h @iteration.name %>
|
10
|
-
</p>
|
11
|
-
|
12
|
-
<p>
|
13
|
-
<b>Start date:</b>
|
14
|
-
<%=h @iteration.start_date %>
|
15
|
-
</p>
|
16
|
-
|
17
|
-
<p>
|
18
|
-
<b>End date:</b>
|
19
|
-
<%=h @iteration.end_date %>
|
20
|
-
</p>
|
21
|
-
|
22
|
-
<p>
|
23
|
-
<b>Release:</b>
|
24
|
-
<%=h @iteration.release.release_date if @iteration.release %>
|
25
|
-
</p>
|
26
|
-
|
27
|
-
<% unless @iteration.stories.empty? %>
|
28
|
-
<b>Stories</b>
|
29
|
-
<ul>
|
30
|
-
<% @iteration.stories.each do |story| %>
|
31
|
-
|
32
|
-
<li><%= story.description %> | <%= story.points %></li>
|
33
|
-
|
34
|
-
<% end %>
|
35
|
-
</ul>
|
36
|
-
<% end %>
|
37
|
-
<%= link_to 'Edit', edit_iteration_path(@iteration) %> |
|
38
|
-
<%= link_to 'Back', iterations_path %>
|
1
|
+
<div id="burndown_chart">
|
2
|
+
<%= burndown_chart @iteration, @iteration_data %>
|
39
3
|
</div>
|
40
4
|
|
41
|
-
<div
|
42
|
-
|
5
|
+
<div id="iteration_stats">
|
6
|
+
<h3>Iteration Stats</h3>
|
7
|
+
|
8
|
+
<p>
|
9
|
+
<b>Velocity:</b>
|
10
|
+
<%=h @iteration.velocity %>
|
11
|
+
</p>
|
12
|
+
|
13
|
+
<p>
|
14
|
+
<b>Name:</b>
|
15
|
+
<%=h @iteration.name %>
|
16
|
+
</p>
|
17
|
+
|
18
|
+
<p>
|
19
|
+
<b>Start date:</b>
|
20
|
+
<%=h @iteration.start_date %>
|
21
|
+
</p>
|
22
|
+
|
23
|
+
<p>
|
24
|
+
<b>End date:</b>
|
25
|
+
<%=h @iteration.end_date %>
|
26
|
+
</p>
|
27
|
+
|
28
|
+
<p>
|
29
|
+
<b>Release:</b>
|
30
|
+
<%=h @iteration.release.release_date if @iteration.release %>
|
31
|
+
</p>
|
32
|
+
|
33
|
+
<% unless @iteration.stories.empty? %>
|
34
|
+
<b>Stories</b>
|
35
|
+
<ul>
|
36
|
+
<% @iteration.stories.each do |story| %>
|
37
|
+
|
38
|
+
<li><%= story.description %> | <%= story.points %></li>
|
39
|
+
|
40
|
+
<% end %>
|
41
|
+
</ul>
|
42
|
+
<% end %>
|
43
43
|
</div>
|
44
|
+
|
45
|
+
<%= link_to 'Edit', edit_iteration_path(@iteration) %> |
|
46
|
+
<%= link_to 'Back', iterations_path %> |
|
47
|
+
<%=link_to 'Stories', iteration_stories_path(@iteration) %>
|
48
|
+
|
49
|
+
|
44
50
|
|
@@ -72,3 +72,5 @@ div.preconditions ol li, div.outcomes ol li { margin:2px; font-size:0.95em;}
|
|
72
72
|
div.story-props {display:block;height:30px;border-bottom:1px dotted grey;padding-top:4px;}
|
73
73
|
div.story-props div {display:inline-block;float:left;margin-left:20px;line-height:25px;}
|
74
74
|
|
75
|
+
#burndown_chart { margin-left:auto; margin-right:auto; width:800px; }
|
76
|
+
#iteration_stats { margin-top : 30px; }
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: branston
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- dave.hrycyszyn@headlondon.com
|
@@ -11,7 +11,7 @@ autorequire:
|
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
13
|
|
14
|
-
date: 2010-01-
|
14
|
+
date: 2010-01-13 00:00:00 +00:00
|
15
15
|
default_executable: branston
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|