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.
@@ -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
- else
64
- format.html { render_optional_error_file 404 }
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
- end
69
-
70
- # GET /stories/new
71
- # GET /stories/new.xml
72
- def new
73
- @story = Story.new
74
-
75
- respond_to do |format|
76
- format.html # new.html.erb
77
- format.xml { render :xml => @story }
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
- end
80
-
81
- # GET /stories/1/edit
82
- def edit
83
- @story = Story.find_by_slug(params[:id])
84
- end
85
-
86
- # POST /stories
87
- # POST /stories.xml
88
- def create
89
- @story = Story.new(params[:story])
90
- @story.author = current_user
91
- @story.iteration = @iteration
92
-
93
- respond_to do |format|
94
- if @story.save
95
- flash[:notice] = 'Story was successfully created.'
96
- format.html { redirect_to iteration_stories_url(@iteration) }
97
- format.xml { render :xml => @story, :status => :created, :location => @story }
98
- else
99
- format.html { render :action => "new" }
100
- format.xml { render :xml => @story.errors, :status => :unprocessable_entity }
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
- end
104
-
105
- # PUT /stories/1
106
- # PUT /stories/1.xml
107
- def update
108
- @story = Story.find_by_slug(params[:id])
109
- respond_to do |format|
110
- if @story.update_attributes(params[:story])
111
- flash[:notice] = 'Story was successfully updated.'
112
- format.html { redirect_to iteration_story_path(@iteration, @story) }
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
- end
121
-
122
- # DELETE /stories/1
123
- # DELETE /stories/1.xml
124
- def destroy
125
- @story = Story.find_by_slug(params[:id])
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 = 0
8
- points_data = []
9
-
6
+
7
+ total_points = iteration.velocity
8
+ running_total = 0
9
+
10
10
  unless data.nil? or data.empty?
11
- total_points = data[0].total_points.to_i
12
- points_data = data.collect{|d| d.points.to_i}
13
- end
14
-
15
- work_days = []
16
- (iteration.start_date.to_date..iteration.end_date.to_date).to_a.each do |date|
17
- work_days.push date.strftime('%d/%m') unless date.wday == 0 or date.wday == 6
18
- end
19
-
20
- # Keep adding the last value to flatline the chart
21
- while work_days.length > data.length
22
- data.push data[data.length - 1]
23
- end
24
-
25
- # Make some gradations for the y axis labels
26
- y_scale = [0]
27
- [4, 2, 1.5, 1.25, 1].each do |n|
28
- unit = (total_points / n).floor
29
- y_scale.push unit if unit > 0
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
- Iteration.find_by_sql [
32
- "SELECT SUM(points) AS total_points,
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", id
37
+ GROUP BY completed_date
38
+ ORDER bY completed_date", id
39
39
  ]
40
40
  end
41
41
 
@@ -62,6 +62,8 @@ class Story < ActiveRecord::Base
62
62
  story.completed_date = Date.today
63
63
  end
64
64
  end
65
+
66
+ attr_protected :status
65
67
 
66
68
  def to_param
67
69
  title.parameterize
@@ -1,44 +1,50 @@
1
- <div style="width:38%;float:left">
2
- <p>
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 style="width:58%;float:right">
42
- <%= burndown_chart @iteration, @iteration_data %>
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.5
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-07 00:00:00 +00:00
14
+ date: 2010-01-13 00:00:00 +00:00
15
15
  default_executable: branston
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency