Commit 76f71df34ce9bd51e06a3b43d44f63818533f12d
Exists in
send_email_to_admins
and in
5 other branches
Merge branch 'master_processed_tasks' into 'master'
Improves listing of processed tasks - Filters for processed tasks Signed-off-by: Gustavo Jaruga <darksshades@gmail.com> Signed-off-by: Marcos Ronaldo <marcos.rpj2@gmail.com> See merge request !833
Showing
7 changed files
with
185 additions
and
11 deletions
Show diff stats
app/controllers/my_profile/tasks_controller.rb
| ... | ... | @@ -26,7 +26,11 @@ class TasksController < MyProfileController |
| 26 | 26 | end |
| 27 | 27 | |
| 28 | 28 | def processed |
| 29 | - @tasks = Task.to(profile).without_spam.closed.sort_by(&:created_at) | |
| 29 | + @tasks = Task.to(profile).without_spam.closed.order('tasks.created_at DESC') | |
| 30 | + @filter = params[:filter] || {} | |
| 31 | + @tasks = filter_tasks(@filter, @tasks) | |
| 32 | + @tasks = @tasks.paginate(:per_page => Task.per_page, :page => params[:page]) | |
| 33 | + @task_types = Task.closed_types_for(profile) | |
| 30 | 34 | end |
| 31 | 35 | |
| 32 | 36 | def change_responsible |
| ... | ... | @@ -102,4 +106,28 @@ class TasksController < MyProfileController |
| 102 | 106 | render :json => result.map { |task| {:label => task.data[:name], :value => task.data[:name]} } |
| 103 | 107 | end |
| 104 | 108 | |
| 109 | + protected | |
| 110 | + | |
| 111 | + def filter_tasks(filter, tasks) | |
| 112 | + tasks = tasks.eager_load(:requestor, :closed_by) | |
| 113 | + tasks = tasks.of(filter[:type].presence) | |
| 114 | + tasks = tasks.where(:status => filter[:status]) unless filter[:status].blank? | |
| 115 | + | |
| 116 | + filter[:created_from] = Date.parse(filter[:created_from]) unless filter[:created_from].blank? | |
| 117 | + filter[:created_until] = Date.parse(filter[:created_until]) unless filter[:created_until].blank? | |
| 118 | + filter[:closed_from] = Date.parse(filter[:closed_from]) unless filter[:closed_from].blank? | |
| 119 | + filter[:closed_until] = Date.parse(filter[:closed_until]) unless filter[:closed_until].blank? | |
| 120 | + | |
| 121 | + tasks = tasks.from_creation_date filter[:created_from] unless filter[:created_from].blank? | |
| 122 | + tasks = tasks.until_creation_date filter[:created_until] unless filter[:created_until].blank? | |
| 123 | + | |
| 124 | + tasks = tasks.from_closed_date filter[:closed_from] unless filter[:closed_from].blank? | |
| 125 | + tasks = tasks.until_closed_date filter[:closed_until] unless filter[:closed_until].blank? | |
| 126 | + | |
| 127 | + tasks = tasks.where('profiles.name LIKE ?', filter[:requestor]) unless filter[:requestor].blank? | |
| 128 | + tasks = tasks.where('closed_bies_tasks.name LIKE ?', filter[:closed_by]) unless filter[:closed_by].blank? | |
| 129 | + tasks = tasks.where('tasks.data LIKE ?', "%#{filter[:text]}%") unless filter[:text].blank? | |
| 130 | + tasks | |
| 131 | + end | |
| 132 | + | |
| 105 | 133 | end | ... | ... |
app/models/task.rb
| ... | ... | @@ -324,11 +324,30 @@ class Task < ActiveRecord::Base |
| 324 | 324 | where [environment_condition, profile_condition].compact.join(' OR ') |
| 325 | 325 | } |
| 326 | 326 | |
| 327 | + scope :from_closed_date, -> closed_from { | |
| 328 | + where('tasks.end_date >= ?', closed_from.beginning_of_day) unless closed_from.blank? | |
| 329 | + } | |
| 330 | + | |
| 331 | + scope :until_closed_date, -> closed_until { | |
| 332 | + where('tasks.end_date <= ?', closed_until.end_of_day) unless closed_until.blank? | |
| 333 | + } | |
| 334 | + | |
| 335 | + scope :from_creation_date, -> created_from { | |
| 336 | + where('tasks.created_at >= ?', created_from.beginning_of_day) unless created_from.blank? | |
| 337 | + } | |
| 338 | + | |
| 339 | + scope :until_creation_date, -> created_until { | |
| 340 | + where('tasks.created_at <= ?', created_until.end_of_day) unless created_until.blank? | |
| 341 | + } | |
| 327 | 342 | |
| 328 | 343 | def self.pending_types_for(profile) |
| 329 | 344 | Task.to(profile).pending.select('distinct type').map { |t| [t.class.name, t.title] } |
| 330 | 345 | end |
| 331 | 346 | |
| 347 | + def self.closed_types_for(profile) | |
| 348 | + Task.to(profile).closed.select('distinct type').map { |t| [t.class.name, t.title] } | |
| 349 | + end | |
| 350 | + | |
| 332 | 351 | def opened? |
| 333 | 352 | status == Task::Status::ACTIVE || status == Task::Status::HIDDEN |
| 334 | 353 | end | ... | ... |
| ... | ... | @@ -0,0 +1,23 @@ |
| 1 | +<div class="title"> | |
| 2 | + <%= task_information(task) %> | |
| 3 | +</div> | |
| 4 | +<div class="status"> | |
| 5 | + <%= _(Task::Status.names[task.status]) %> | |
| 6 | +</div> | |
| 7 | +<div class="dates"> | |
| 8 | + <span class="created"> | |
| 9 | + <span class="label"><%= _('Created:') %></span> | |
| 10 | + <span class="value"><%= show_date(task.created_at) %></span> | |
| 11 | + </span> | |
| 12 | + — | |
| 13 | + <span class="processed"> | |
| 14 | + <span class="label"><%= _('Processed:') %></span> | |
| 15 | + <span class="value"><%= show_date(task.end_date) %></span> | |
| 16 | + </span> | |
| 17 | +</div> | |
| 18 | +<% if task.closed_by.present? %> | |
| 19 | + <div class="closed-by"> | |
| 20 | + <span class="label"><%= _('Closed by:') %></span> | |
| 21 | + <span class="value"><%= link_to(task.closed_by.name, task.closed_by.url) %></span> | |
| 22 | + </div> | |
| 23 | +<% end %> | ... | ... |
app/views/tasks/index.html.erb
| ... | ... | @@ -57,7 +57,9 @@ |
| 57 | 57 | <% end %> |
| 58 | 58 | |
| 59 | 59 | <div class="task_boxes"> |
| 60 | - <%= render :partial => 'task', :collection => @tasks %> | |
| 60 | + <% @tasks.each do |task| %> | |
| 61 | + <%= render :partial => partial_for_class(task.class, nil, nil), :locals => {:task => task} %> | |
| 62 | + <% end %> | |
| 61 | 63 | </div> |
| 62 | 64 | |
| 63 | 65 | <% unless @view_only %> | ... | ... |
app/views/tasks/processed.html.erb
| 1 | +<%= stylesheet_link_tag 'tasks' %> | |
| 2 | + | |
| 3 | +<div class="task-processed"> | |
| 1 | 4 | <h1><%= _("%s's processed tasks") % profile.name %></h1> |
| 2 | 5 | |
| 6 | +<div class="task-processed-filter"> | |
| 7 | +<% | |
| 8 | + type_collection = [[nil, _('All')]] + @task_types | |
| 9 | + type_collection.map!{|first,last| [last,first]} | |
| 10 | +%> | |
| 11 | + <%= form_tag '#', :method => 'get' do %> | |
| 12 | + <%= field_set_tag _('Filter'), :class => 'filter_fields' do %> | |
| 13 | + <div> | |
| 14 | + <%= labelled_form_field(_('Type of task')+': ', select_tag('filter[type]', options_for_select(type_collection, @filter[:type]), {:id => 'filter-type'})) %> | |
| 15 | + <%= labelled_form_field(_('Status')+': ', select_tag('filter[status]', options_for_select([[_('Any'), nil], [_(Task::Status.names[Task::Status::CANCELLED]), 2], [_(Task::Status.names[Task::Status::FINISHED]), 3] ], @filter[:status]))) %> | |
| 16 | + </div> | |
| 17 | + | |
| 18 | + <div> | |
| 19 | + <%= labelled_form_field(_('Text Filter:'), text_field_tag('filter[text]', @filter[:text])) %> | |
| 20 | + </div> | |
| 21 | + | |
| 22 | + <div> | |
| 23 | + <%= labelled_form_field(_('Requestor:'), text_field_tag('filter[requestor]', @filter[:requestor])) %> | |
| 24 | + <%= labelled_form_field(_('Closed by:'), text_field_tag('filter[closed_by]', @filter[:closed_by])) %> | |
| 25 | + </div> | |
| 26 | + <%= labelled_form_field(_('Creation date'), date_range_field('filter[created_from]', 'filter[created_until]', @filter[:created_from], @filter[:created_until], { :change_month => true, :change_year => true, :date_format => 'yy-mm-dd' }, { :size => 14, :from_id => 'filter_created_from', :to_id => 'filter_created_until' })) %> | |
| 27 | + <%= labelled_form_field(_('Processed date'), date_range_field('filter[closed_from]', 'filter[closed_until]', @filter[:closed_from], @filter[:closed_until], { :change_month => true, :change_year => true, :date_format => 'yy-mm-dd' }, { :size => 14, :from_id => 'filter_closed_from', :to_id => 'filter_closed_until' })) %> | |
| 28 | + | |
| 29 | + <div class="actions"> | |
| 30 | + <%= submit_button(:search, _('Search')) %> | |
| 31 | + </div> | |
| 32 | + <% end %> | |
| 33 | + <% end %> | |
| 34 | +</div> | |
| 35 | + | |
| 3 | 36 | <p> |
| 4 | 37 | <% if @tasks.empty? %> |
| 5 | 38 | <em><%= _('No processed tasks.') %></em> |
| 6 | 39 | <% else %> |
| 7 | - <ul> | |
| 40 | + <ul class="task-list"> | |
| 8 | 41 | <% @tasks.each do |item| %> |
| 9 | - <li> | |
| 10 | - <strong><%= task_information(item) %></strong> <br/> | |
| 11 | - <small> | |
| 12 | - <%= _('Created:') +' '+ show_date(item.created_at) %> | |
| 13 | - — | |
| 14 | - <%= _('Processed:') +' '+ show_date(item.end_date) %> | |
| 15 | - </small> | |
| 42 | + <li class="task status-<%= item.status%>"> | |
| 43 | + <%= render :partial => partial_for_class(item.class, nil, 'processed'), :locals => {:task => item} %> | |
| 16 | 44 | </li> |
| 17 | 45 | <% end %> |
| 18 | 46 | </ul> |
| 47 | + <%= pagination_links(@tasks)%> | |
| 19 | 48 | <% end %> |
| 20 | 49 | </p> |
| 21 | 50 | |
| 22 | 51 | <% button_bar do %> |
| 23 | 52 | <%= button(:back, _('Back'), :action => 'index') %> |
| 24 | 53 | <% end %> |
| 54 | + | |
| 55 | +</div> | ... | ... |
public/stylesheets/tasks.scss
| ... | ... | @@ -82,3 +82,47 @@ div.pending-tasks { |
| 82 | 82 | .task_responsible { |
| 83 | 83 | text-align: right; |
| 84 | 84 | } |
| 85 | + | |
| 86 | +.task-processed li { | |
| 87 | + background-color: rgb(240, 240, 240); | |
| 88 | + border-radius: 8px; | |
| 89 | + margin: 10px 0; | |
| 90 | + list-style-type: none; | |
| 91 | + padding: 12px; | |
| 92 | +} | |
| 93 | + | |
| 94 | +.task-processed .task.status-3 { | |
| 95 | + background-color: rgb(205, 252, 218); | |
| 96 | +} | |
| 97 | + | |
| 98 | +.task-processed .task.status-2 { | |
| 99 | + background-color: rgb(255, 203, 203); | |
| 100 | +} | |
| 101 | + | |
| 102 | +.task-processed ul { | |
| 103 | + padding: 0; | |
| 104 | +} | |
| 105 | + | |
| 106 | +.task-processed .task-list .task .title { | |
| 107 | + border-bottom: 1px solid rgba(0, 0, 0, 0.1); | |
| 108 | + font-weight: bold; | |
| 109 | + color: rgb(44, 44, 44); | |
| 110 | +} | |
| 111 | + | |
| 112 | +.task-processed .task .status { | |
| 113 | + float: right; | |
| 114 | + color: rgb(156, 156, 156); | |
| 115 | + font-weight: bold; | |
| 116 | +} | |
| 117 | + | |
| 118 | +.task-processed .task .dates { | |
| 119 | + font-size: 11px; | |
| 120 | +} | |
| 121 | + | |
| 122 | +.task-processed .task .closed-by { | |
| 123 | + font-size: 11px; | |
| 124 | +} | |
| 125 | + | |
| 126 | +.task-processed .task .label { | |
| 127 | + font-weight: bold | |
| 128 | +} | ... | ... |
test/functional/tasks_controller_test.rb
| ... | ... | @@ -75,7 +75,8 @@ class TasksControllerTest < ActionController::TestCase |
| 75 | 75 | |
| 76 | 76 | assert_response :success |
| 77 | 77 | assert_template 'processed' |
| 78 | - assert_kind_of Array, assigns(:tasks) | |
| 78 | + assert !assigns(:tasks).nil? | |
| 79 | + assert_kind_of ActiveRecord::Relation, assigns(:tasks) | |
| 79 | 80 | end |
| 80 | 81 | |
| 81 | 82 | should 'display task created_at' do |
| ... | ... | @@ -762,4 +763,30 @@ class TasksControllerTest < ActionController::TestCase |
| 762 | 763 | assert_equal [email_template], assigns(:rejection_email_templates) |
| 763 | 764 | end |
| 764 | 765 | |
| 766 | + should 'filter processed tasks by all filters' do | |
| 767 | + requestor = fast_create(Person) | |
| 768 | + closed_by = fast_create(Person) | |
| 769 | + class AnotherTask < Task; end | |
| 770 | + | |
| 771 | + created_date = DateTime.now | |
| 772 | + processed_date = DateTime.now | |
| 773 | + | |
| 774 | + task_params = {:status => Task::Status::FINISHED, :requestor => requestor, :target => profile, :created_at => created_date, :end_date => processed_date, :closed_by => closed_by, :data => {:field => 'some data field'}} | |
| 775 | + | |
| 776 | + task = create(AnotherTask, task_params) | |
| 777 | + create(Task, task_params) | |
| 778 | + create(AnotherTask, task_params.clone.merge(:status => Task::Status::CANCELLED)) | |
| 779 | + create(AnotherTask, task_params.clone.merge(:created_at => created_date - 1.day)) | |
| 780 | + create(AnotherTask, task_params.clone.merge(:created_at => created_date + 1.day)) | |
| 781 | + create(AnotherTask, task_params.clone.merge(:end_date => processed_date - 1.day)) | |
| 782 | + create(AnotherTask, task_params.clone.merge(:end_date => processed_date + 1.day)) | |
| 783 | + create(AnotherTask, task_params.clone.merge(:requestor => fast_create(Person, :name => 'another-requestor'))) | |
| 784 | + create(AnotherTask, task_params.clone.merge(:closed_by => fast_create(Person, :name => 'another-closer'))) | |
| 785 | + create(AnotherTask, task_params.clone.merge(:data => {:field => "other data field"})) | |
| 786 | + | |
| 787 | + get :processed, :filter => {:type => AnotherTask, :status => Task::Status::FINISHED, :created_from => created_date, :created_until => created_date, :closed_from => processed_date, :closed_until => processed_date, :requestor => requestor.name, :closed_by => closed_by.name, :text => "some data field"} | |
| 788 | + assert_response :success | |
| 789 | + assert_equal [task], assigns(:tasks) | |
| 790 | + end | |
| 791 | + | |
| 765 | 792 | end | ... | ... |