backlog 0.17.5 → 0.17.6

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,19 @@
1
+ == 0.17.6 2008-01-17
2
+
3
+ === Features
4
+
5
+ * Allowed moving a task from one backlog to another.
6
+ * Added simple summary to work account view.
7
+
8
+ === Fixes
9
+
10
+ * Minor cosmetic adjustment of task list.
11
+ * Fixed application error when displaying completed tasks.
12
+ * Fixed error when trying to create new task with errors (duplicate description).
13
+ * Fixed showing of work record for earlier years.
14
+ * Made task description bold in task lists for better readability.
15
+ * Changed dependency to rmagick to 1.15.12 instead of newest since rmagick 2 requires very new ImageMagick.
16
+
1
17
  == 0.17.5 2008-01-15
2
18
 
3
19
  === Fixes
data/Rakefile CHANGED
@@ -32,7 +32,7 @@ Hoe.new("backlog", APP::VERSION) do |p|
32
32
  }
33
33
  p.need_zip = true
34
34
  p.url = 'http://rubyforge.org/projects/backlog/'
35
- p.extra_deps = [['rails', '>= 1.2.4'], ['gruff', '>= 0.2.9'], ['rmagick', '>= 1.15.12'], ['postgres', '>= 0.7.9']]
35
+ p.extra_deps = [['rails', '>= 1.2.4'], ['gruff', '>= 0.2.9'], ['rmagick', '= 1.15.12'], ['postgres', '>= 0.7.9']]
36
36
  p.rsync_args = "-av --delete --exclude=wiki*"
37
37
  end
38
38
 
@@ -171,7 +171,7 @@ class BacklogsController < ApplicationController
171
171
  task.save!
172
172
  end
173
173
  end
174
- render :text => 'Updated sort order'
174
+ render :text => 'alert("Updated sort order");'
175
175
  end
176
176
 
177
177
  private
@@ -196,15 +196,16 @@ class PeriodsController < ApplicationController
196
196
  end
197
197
 
198
198
  def order
199
- params.keys.find {|k| k =~ /active_tasks_(.*)/}
199
+ if params.keys.find {|k| k =~ /active_tasks_(.*)/}
200
200
  period_id = $1
201
- tasks = params["active_tasks_#{period_id}"].select {|id| not id.empty?}
201
+ ids = params["active_tasks_#{period_id}"]
202
+ tasks = ids.select {|id| not id.empty?}
202
203
  tasks.each_with_index do |id,idx|
203
204
  task = Task.find(id)
204
205
  task.insert_at(idx + 1)
205
206
  task.save!
206
207
  end
207
- render :text => 'Updated sort order'
208
+ end
208
209
  end
209
210
 
210
211
  private
@@ -44,12 +44,14 @@ class TasksController < ApplicationController
44
44
  populate_layout
45
45
  @backlogs = Backlog.find(:all, :order => 'name')
46
46
  @periods = Period.find_active_or_future
47
+ @customers = Customer.find(:all)
47
48
  render :action => 'new'
48
49
  end
49
50
  end
50
51
 
51
52
  def edit
52
53
  @task ||= Task.find(params[:id])
54
+ @task.backlog_id = params[:task][:backlog_id] if params[:task] && params[:task][:backlog_id]
53
55
  @task.period_id = params[:task][:period_id] if params[:task] && params[:task][:period_id]
54
56
  @periods = Period.find_active_or_future
55
57
  @backlogs = Backlog.find(:all, :order => 'name')
@@ -14,6 +14,11 @@ class WorkAccountsController < ApplicationController
14
14
 
15
15
  def show
16
16
  @work_account = WorkAccount.find(params[:id])
17
+ works = @work_account.works.select{|w|w.user_id == current_user.id}
18
+ @backlog_totals = works.to_summarized_hash {|work| [work.task && work.task.backlog, work.hours]}
19
+ @task_totals = works.to_summarized_hash {|work| [work.task, work.hours]}
20
+ @task_totals_per_backlog = @task_totals.to_a.to_grouped_hash {|task, hours| [task && task.backlog, [task, hours]]}
21
+ @total_hours = works.inject(BigDecimal('0')) {|total, work| total += work.hours}
17
22
  end
18
23
 
19
24
  def new
@@ -42,7 +42,7 @@ class WorksController < ApplicationController
42
42
  if backlog_name && backlog_name.size > 0 && task_description && task_description.size > 0
43
43
  backlog = Backlog.find_by_name(backlog_name)
44
44
  task = backlog.tasks_with_children.find{|t| t.description == task_description}
45
- params[:work][:task_id] = task.id
45
+ params[:work][:task_id] = task.id if task
46
46
  end
47
47
  account_name = params[:work].delete(:work_account_name)
48
48
  if account_name && account_name.size > 0
@@ -137,8 +137,9 @@ class WorksController < ApplicationController
137
137
  end
138
138
 
139
139
  def weekly_work_sheet
140
- @week = (params[:id] && params[:id].to_i) || Date.today.cweek
141
- @rows = Work.works_for_week(@week)
140
+ @year = (params[:year] && params[:year].to_i) || Date.today.year
141
+ @week = (params[:week] && params[:week].to_i) || Date.today.cweek
142
+ @rows = Work.works_for_week(@year, @week)
142
143
  render :layout => 'wide'
143
144
  end
144
145
 
@@ -1,5 +1,5 @@
1
1
  module WorksHelper
2
2
  def week_date(day)
3
- Date.commercial(Date.today.year, @week, day).strftime('%d/%m')
3
+ Date.commercial(@year, @week, day).strftime('%d/%m')
4
4
  end
5
5
  end
data/app/models/work.rb CHANGED
@@ -30,8 +30,8 @@ class Work < ActiveRecord::Base
30
30
  # [m2, t2, nil,t2, nil,nil, nil],
31
31
  # [nil,t2, nil,nil,nil,nil, nil],
32
32
  # ]
33
- def self.works_for_week(week_no, user = current_user)
34
- first = Date.commercial(Date.today.year, week_no, 1)
33
+ def self.works_for_week(year, week_no, user = current_user)
34
+ first = Date.commercial(year, week_no, 1)
35
35
  last = first + 7
36
36
  works = find(:all, :conditions => "completed_at IS NOT NULL AND started_at BETWEEN '#{first.to_time.iso8601}' AND '#{last.to_time.iso8601}'", :order => 'started_at')
37
37
  length = 0
@@ -98,6 +98,10 @@ class Work < ActiveRecord::Base
98
98
  end
99
99
 
100
100
  def completed_at_time=(new_value)
101
+ if new_value == ''
102
+ self.completed_at = nil
103
+ return
104
+ end
101
105
  raise "invalid time format: #{new_value}" unless new_value =~ /(\d{2}):(\d{2})/
102
106
  new_hour, new_minutes = $1, $2
103
107
  t = completed_at || Time.now
@@ -8,5 +8,9 @@ class WorkAccount < ActiveRecord::Base
8
8
  def enable_invoicing?
9
9
  invoice_code && invoice_code.length > 0
10
10
  end
11
+
12
+ def total_hours
13
+ works.inject(BigDecimal('0')) {|total, work| total + work.hours}
14
+ end
11
15
 
12
16
  end
@@ -22,7 +22,7 @@
22
22
  <% end %>
23
23
  </div>
24
24
  <%for list_id in list_ids %>
25
- <%=sortable_element list_id, :url => { :action => :order }, :containment => list_ids, :constraint => false %>
25
+ <%=sortable_element list_id, :url => { :action => :order }, :containment => list_ids, :constraint => false, :dropOnEmpty => true %>
26
26
  <% end %>
27
27
  <p id="no_tasks_message"<%=' style="display: none;"' if @tasks and not @tasks.empty? %>>
28
28
  <%=l :no_pending_tasks_in_backlog %>
@@ -0,0 +1 @@
1
+ record page, 'alert("hi");'
@@ -47,10 +47,10 @@ function echoRuby(ruby) {
47
47
  alert(Ruby.eval(ruby));
48
48
  }
49
49
 
50
- window.onload = function() {
51
- Ruby.init(function(result) {
52
- alert(result);
53
- });
54
- }
50
+ //window.onload = function() {
51
+ // Ruby.init(function(result) {
52
+ // alert(result);
53
+ // });
54
+ //}
55
55
 
56
56
  </script>
@@ -7,7 +7,7 @@
7
7
  <%=render :partial => '/tasks/fields_header', :locals => {:backlog => @backlog, :active => false, :track_times => false, :work_done => work_done} %>
8
8
  <ul id="completed_tasks_<%=period && period.id%>" class="task_list" style="width: 100%;">
9
9
  <% @completed_tasks.select {|t| t.period == period}.each do |task| %>
10
- <%=render :partial => '/tasks/task', :locals => { :task => task, :i => i, :active => false, :highlight_task => task == @selected_task, :hidden => false } %>
10
+ <%=render :partial => '/tasks/task', :locals => { :task => task, :i => i, :active => false, :highlight_task => task == @selected_task, :hidden => false, :show_backlog => controller.class != BacklogsController } %>
11
11
  <% i += 1 %>
12
12
  <% end %>
13
13
  </ul>
@@ -1,6 +1,6 @@
1
1
  <!--[form:task]-->
2
2
  <p>
3
- <% if @task.backlog.nil? || @task.new_record? %>
3
+ <% if @task.backlog.nil? || @task.new_record? || @task.active? %>
4
4
  <label for="task_backlog_id"><%=l :backlog%></label><br/>
5
5
  <%= select 'task', 'backlog_id', [['', '']] + @backlogs.map{|backlog| [backlog.name, backlog.id]}, {}, :onchange => "form.action = '#{url_for}'; form.submit();" %>
6
6
  <% else %>
@@ -16,9 +16,13 @@
16
16
 
17
17
  <% if @task.backlog && @task.backlog.enable_periods? %>
18
18
  <p><label for="task_period_id"><%=l :period%></label><br/>
19
+ <% if @task.active? %>
19
20
  <%= select 'task', 'period_id', [['', '']] + @periods.map{|p| [p.name, p.id]}, {},
20
21
  :onchange => remote_function(:update => 'period_link',
21
22
  :url => { :controller => 'periods', :action => 'make_link', :id => "'+value+'", :escape => false }) %>
23
+ <% else %>
24
+ <%=detour_to @task.period, :controller => 'periods', :action => :show, :id => @task.period %>
25
+ <% end %>
22
26
  <span id="period_link">
23
27
  <%=render :partial => '/periods/link', :locals => {:period => @task.period}%>
24
28
  </span>
@@ -33,13 +37,15 @@
33
37
  <% if @task.active? -%>
34
38
  <%=text_field 'task', 'description', :size => 64, :maxlength => 80 %>
35
39
  <% else -%>
36
- <%=@task.description -%>
40
+ <b><%=@task.description -%></b>
37
41
  <% end -%>
38
42
  </p>
39
43
 
40
- <% if @task.enable_customer? %>
44
+ <% if @task.enable_customer? && (@task.active? || @task.customer) %>
41
45
  <p><label for="task_customer"><%=l :customer%></label><br/>
46
+ <% if @task.active? %>
42
47
  <%=select 'task', 'customer_id', [['', '']] + @customers.map{|c| [c.name, c.id]} %>
48
+ <% end %>
43
49
  <% if @task.customer %>
44
50
  <%=image_detour_to('customer.png', "#{l(:customer)} #{@task.customer.name}", {:controller => 'customers', :action => :edit, :id => @task.customer}, {:class => 'image-submit', :style => 'vertical-align: bottom'}) %>
45
51
  <% end %>
@@ -53,8 +59,10 @@
53
59
  <%= text_field 'task', 'initial_estimate', :size => 4 %>
54
60
  </p>
55
61
  <% else %>
56
- <p style="float: left"><label for="estimate_todo"><%=l :estimate%></label><br/>
62
+ <% if @task.active? %>
63
+ <p style="float: left; margin-right: 1em"><label for="estimate_todo"><%=l :estimate%></label><br/>
57
64
  <%=text_field 'estimate', 'todo', :size => 4, :value => @task.todo %>
65
+ <% end %>
58
66
  </p>
59
67
  <% end %>
60
68
  <% end %>
@@ -16,7 +16,7 @@
16
16
  <%=detour_to "##{@task.id}", :controller => 'tasks', :action => :edit, :id => @task.id, :style => 'border: 0px; margin: 0px; padding: 0px' if @task.position || @task.depth == 0 %>
17
17
  </div>
18
18
  <div id="task_<%=@task.id%>_description" class="task_description">
19
- <%=h(@task.description) %>
19
+ <b><%=h(@task.description)%></b>
20
20
  <% if show_backlog %>
21
21
  <br/>
22
22
  <%=l :backlog%>: <%=detour_to(h(@task.backlog.name), :controller => 'backlogs', :action => :show, :id => @task.backlog) %>
@@ -36,7 +36,7 @@ function handleEvent(field, event, id) {
36
36
  </script>
37
37
 
38
38
  <% if @tasks %>
39
- <%=render :partial => '/tasks/fields_header', :locals => {:backlog => nil, :active => true, :track_times => @tasks.find {|t|t.period && t.period.active?}} %>
39
+ <%=render :partial => '/tasks/fields_header', :locals => {:backlog => nil, :active => true, :track_todo => @tasks.find {|t|t.track_todo?}, :track_done => @tasks.find {|t|t.track_done?}, :track_times => @tasks.find {|t|t.period && t.period.active?}} %>
40
40
  <ul class="task_list">
41
41
  <% i = 0 %>
42
42
  <% current_backlog = nil %>
@@ -1,8 +1,33 @@
1
- <% for column in WorkAccount.content_columns %>
2
- <p>
3
- <b><%= column.human_name %>:</b> <%=h @work_account.send(column.name) %>
4
- </p>
5
- <% end %>
1
+ <% @page_title = "#{l(:work_account)} #{l(:work_account)}" %>
6
2
 
7
- <%= link_to 'Edit', :action => 'edit', :id => @work_account %> |
8
- <%= link_to 'Back', :action => 'list' %>
3
+ <div id="spotlight">
4
+ <div class="btitle">
5
+ <h4><%=@work_account.name%></h4>
6
+ </div>
7
+
8
+ <table>
9
+ <% for backlog in @backlog_totals.keys %>
10
+ <tr>
11
+ <th><%=backlog ? backlog.name : l(:no_backlog)%></th>
12
+ <th><%=@backlog_totals[backlog]%></th>
13
+ </tr>
14
+ <% for task, hours in @task_totals_per_backlog[backlog] %>
15
+ <tr>
16
+ <td>
17
+ <% if task %>
18
+ <%=link_to task.description, :controller => 'tasks', :action => :edit, :id => task.id %>
19
+ <% end %>
20
+ </td>
21
+ <td align="right" valign="top"><%='%.2f' % hours%></td>
22
+ </tr>
23
+ <% end %>
24
+ <% end %>
25
+ <tr>
26
+ <th>Total hours</th>
27
+ <th><%=@total_hours%></th>
28
+ </tr>
29
+ </table>
30
+
31
+ <%= link_to 'Edit', :action => 'edit', :id => @work_account %> |
32
+ <%= link_to 'Back', :action => 'list' %>
33
+ </div>
@@ -18,6 +18,7 @@
18
18
  <%=render :partial => 'row_field', :locals => {:field => 'started_at_time'} %>
19
19
  </td>
20
20
  <td align="right">
21
+ <%=render :partial => 'row_field', :locals => {:field => 'completed_at_time'} %>
21
22
  </td>
22
23
  <td align="right">
23
24
  <% remote_form_for :work, :url => {:action => :update_row, :id => @work.id} do |f|%>
@@ -5,8 +5,8 @@
5
5
  <% invoicing = @rows.find {|r| r.find {|w| w && w.work_account.enable_invoicing?}} %>
6
6
  <% columns = 2 + (track_times ? 2 : 0) + (invoicing ? 1 : 0) %>
7
7
 
8
- <div style="float: left"><%=link_to(image_tag('arrow_left.png'), :id => (@week - 1))%></div>
9
- <div style="float: right"><%=link_to(image_tag('arrow_right.png'), :id => (@week + 1))%></div>
8
+ <div style="float: left"><%=link_to(image_tag('arrow_left.png'), :year => (@week > 1 ? @year : @year - 1), :week => (@week > 1 ? @week - 1 : 52))%></div>
9
+ <div style="float: right"><%=link_to(image_tag('arrow_right.png'), :year => (@week < 52 ? @year : @year + 1), :week => (@week < 52 ? @week + 1 : 1))%></div>
10
10
 
11
11
  <h1>Work for week <%=@week%><%=user? ? " for #{user.login}" : ''%></h1>
12
12
 
data/config/routes.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  ActionController::Routing::Routes.draw do |map|
2
2
  map.connect '', :controller => "welcome"
3
+ map.connect ':controller/:action/:year/:week'
3
4
  map.connect ':controller/:action/:id.:format'
4
5
  map.connect ':controller/:action/:id'
5
6
  end
data/lib/array_helper.rb CHANGED
@@ -6,5 +6,37 @@ class Array
6
6
  end
7
7
  calculated_value
8
8
  end
9
+
10
+ def to_freq_hash
11
+ freq = {}
12
+ each do |e|
13
+ freq[e] = freq[e].to_i + 1
14
+ end
15
+ freq
16
+ end
17
+
18
+ def to_summarized_hash(operation_symbol = :+)
19
+ sums = {}
20
+ each do |e|
21
+ key, value = yield(e)
22
+ if sums[key]
23
+ sums[key] = sums[key].send(operation_symbol, value)
24
+ else
25
+ sums[key] = value
26
+ end
27
+ end
28
+ sums
29
+ end
30
+
31
+ def to_grouped_hash
32
+ groups = {}
33
+ each do |e|
34
+ key, value = yield(e)
35
+ groups[key] ||= []
36
+ groups[key] << value
37
+ end
38
+ groups
39
+ end
40
+
9
41
  end
10
42
 
@@ -16,7 +16,7 @@ table.input td {vertical-align: top; margin: 0; border: 0; padding: 0 1px;}
16
16
  .task_list {width: 100%; text-align: left; list-style-type: none; padding-left: 0}
17
17
  .task_list li {margin-left: 0}
18
18
  .tasks {cursor: move}
19
- .task_id {float: left; padding-left: 2px; width: 3em; text-align: center}
19
+ .task_id {float: left; padding-left: 2px; width: 3.5em; text-align: center}
20
20
  .task_description {float: left; padding: 1px; width: auto}
21
21
  .task_start {float: left; width: 5em; text-align: center}
22
22
  .task_end_work {float: left; width: 2em}
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: backlog
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.5
4
+ version: 0.17.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Uwe Kubosch
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-01-15 00:00:00 +01:00
12
+ date: 2008-01-19 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -35,7 +35,7 @@ dependencies:
35
35
  version_requirement:
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "="
39
39
  - !ruby/object:Gem::Version
40
40
  version: 1.15.12
41
41
  version:
@@ -81,6 +81,7 @@ files:
81
81
  - app/views/periods/move_task_to_period.rjs
82
82
  - app/views/periods/edit.rhtml
83
83
  - app/views/periods/_form.rhtml
84
+ - app/views/periods/order.rjs
84
85
  - app/views/periods/show.rhtml
85
86
  - app/views/welcome
86
87
  - app/views/redirect.rjs