From fd51b07e21c9e39bbd1ab50a3a93b65dd02ea800 Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 1 May 2015 21:14:16 +0200 Subject: [PATCH 1/3] Allow editing recurring task groups, basic functionality for #152 --- app/controllers/tasks_controller.rb | 2 ++ app/models/periodic_task_group.rb | 14 ++++++++++++++ app/views/tasks/_form.html.haml | 2 +- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/app/controllers/tasks_controller.rb b/app/controllers/tasks_controller.rb index c7e46250..00eca4c4 100644 --- a/app/controllers/tasks_controller.rb +++ b/app/controllers/tasks_controller.rb @@ -42,9 +42,11 @@ class TasksController < ApplicationController def update @task = Task.find(params[:id]) + task_group = @task.periodic_task_group was_periodic = @task.periodic? @task.attributes=(params[:task]) if @task.errors.empty? && @task.save + task_group.update_tasks_including(@task) if params[:periodic] flash[:notice] = I18n.t('tasks.update.notice') if was_periodic && !@task.periodic? flash[:notice] = I18n.t('tasks.update.notice_converted') diff --git a/app/models/periodic_task_group.rb b/app/models/periodic_task_group.rb index 5e8d2e69..6caa598d 100644 --- a/app/models/periodic_task_group.rb +++ b/app/models/periodic_task_group.rb @@ -25,6 +25,20 @@ class PeriodicTaskGroup < ActiveRecord::Base end end + def update_tasks_including(template_task) + group_tasks = tasks + [template_task] + tasks.each do |task| + task.update!(name: template_task.name, + description: template_task.description, + duration: template_task.duration, + required_users: template_task.required_users, + workgroup: template_task.workgroup) + end + group_tasks.each do |task| + task.update_columns(periodic_task_group_id: self.id) + end + end + protected # @return [Number] Number of days between two periodic tasks diff --git a/app/views/tasks/_form.html.haml b/app/views/tasks/_form.html.haml index 78925c41..a2bf0ac2 100644 --- a/app/views/tasks/_form.html.haml +++ b/app/views/tasks/_form.html.haml @@ -26,6 +26,6 @@ = f.input :done .form-actions = f.submit class: 'btn btn-primary' - - if @task.new_record? + - if @task.new_record? or @task.periodic? = f.submit t('.submit.periodic'), name: 'periodic', class: 'btn' = link_to t('ui.or_cancel'), :back From a8a434ef7b69e805b8a01e38c63b4f08a5419bfe Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 1 May 2015 21:31:06 +0200 Subject: [PATCH 2/3] Move due date according to delta --- app/controllers/tasks_controller.rb | 3 ++- app/models/periodic_task_group.rb | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/controllers/tasks_controller.rb b/app/controllers/tasks_controller.rb index 00eca4c4..1e3cd955 100644 --- a/app/controllers/tasks_controller.rb +++ b/app/controllers/tasks_controller.rb @@ -44,9 +44,10 @@ class TasksController < ApplicationController @task = Task.find(params[:id]) task_group = @task.periodic_task_group was_periodic = @task.periodic? + prev_due_date = @task.due_date @task.attributes=(params[:task]) if @task.errors.empty? && @task.save - task_group.update_tasks_including(@task) if params[:periodic] + task_group.update_tasks_including(@task, prev_due_date) if params[:periodic] flash[:notice] = I18n.t('tasks.update.notice') if was_periodic && !@task.periodic? flash[:notice] = I18n.t('tasks.update.notice_converted') diff --git a/app/models/periodic_task_group.rb b/app/models/periodic_task_group.rb index 6caa598d..b7ccceeb 100644 --- a/app/models/periodic_task_group.rb +++ b/app/models/periodic_task_group.rb @@ -25,14 +25,16 @@ class PeriodicTaskGroup < ActiveRecord::Base end end - def update_tasks_including(template_task) + def update_tasks_including(template_task, prev_due_date) group_tasks = tasks + [template_task] + due_date_delta = template_task.due_date - prev_due_date tasks.each do |task| task.update!(name: template_task.name, description: template_task.description, duration: template_task.duration, required_users: template_task.required_users, - workgroup: template_task.workgroup) + workgroup: template_task.workgroup, + due_date: task.due_date + due_date_delta) end group_tasks.each do |task| task.update_columns(periodic_task_group_id: self.id) From a00e7c94bece8d85da2c786f40a7196517f3f5d0 Mon Sep 17 00:00:00 2001 From: wvengen Date: Fri, 8 May 2015 17:39:20 +0200 Subject: [PATCH 3/3] Rework user-interface for editing recurring tasks --- app/controllers/tasks_controller.rb | 30 +++++++++--------- app/views/tasks/_form.html.haml | 42 +++++++------------------ app/views/tasks/_form_sidebar.html.haml | 15 +++++++++ app/views/tasks/edit.haml | 16 ++++++++-- app/views/tasks/new.haml | 9 +++++- app/views/tasks/show.haml | 16 +++++++--- config/locales/en.yml | 9 ++++-- 7 files changed, 79 insertions(+), 58 deletions(-) create mode 100644 app/views/tasks/_form_sidebar.html.haml diff --git a/app/controllers/tasks_controller.rb b/app/controllers/tasks_controller.rb index 1e3cd955..9fd7211e 100644 --- a/app/controllers/tasks_controller.rb +++ b/app/controllers/tasks_controller.rb @@ -1,21 +1,21 @@ # encoding: utf-8 class TasksController < ApplicationController #auto_complete_for :user, :nick - + def index @non_group_tasks = Task.non_group.includes(assignments: :user) @groups = Workgroup.includes(open_tasks: {assignments: :user}) end - + def user @unaccepted_tasks = Task.unaccepted_tasks_for(current_user) @accepted_tasks = Task.accepted_tasks_for(current_user) end - + def new @task = Task.new(current_user_id: current_user.id) end - + def create @task = Task.new(params[:task]) if params[:periodic] @@ -27,19 +27,17 @@ class TasksController < ApplicationController render :template => "tasks/new" end end - + def show @task = Task.find(params[:id]) end - + def edit @task = Task.find(params[:id]) + @periodic = !!params[:periodic] @task.current_user_id = current_user.id - if @task.periodic? - flash.now[:alert] = I18n.t('tasks.edit.warning_periodic').html_safe - end end - + def update @task = Task.find(params[:id]) task_group = @task.periodic_task_group @@ -61,7 +59,7 @@ class TasksController < ApplicationController render :template => "tasks/edit" end end - + def destroy task = Task.find(params[:id]) # Save user_ids to update apple statistics after destroy @@ -76,7 +74,7 @@ class TasksController < ApplicationController redirect_to tasks_url, :notice => I18n.t('tasks.destroy.notice') end - + # assign current_user to the task and set the assignment to "accepted" # if there is already an assignment, only accepted will be set to true def accept @@ -88,23 +86,23 @@ class TasksController < ApplicationController end redirect_to user_tasks_path, :notice => I18n.t('tasks.accept.notice') end - + # deletes assignment between current_user and given task def reject Task.find(params[:id]).users.delete(current_user) redirect_to :action => "index" end - + def set_done Task.find(params[:id]).update_attribute :done, true redirect_to tasks_url, :notice => I18n.t('tasks.set_done.notice') end - + # Shows all tasks, which are already done def archive @tasks = Task.done.page(params[:page]).per(@per_page).order('tasks.updated_on DESC').includes(assignments: :user) end - + # shows workgroup (normal group) to edit weekly_tasks_template def workgroup @group = Group.find(params[:workgroup_id]) diff --git a/app/views/tasks/_form.html.haml b/app/views/tasks/_form.html.haml index a2bf0ac2..077836ba 100644 --- a/app/views/tasks/_form.html.haml +++ b/app/views/tasks/_form.html.haml @@ -1,31 +1,11 @@ -- content_for :javascript do - :javascript - $(function() { - $("#task_user_list").tokenInput("#{users_path(:format => :json)}", { - crossDomain: false, - prePopulate: $("#task_user_list").data("pre"), - hintText: '#{escape_javascript(t('.search.hint'))}', - noResultText: '#{escape_javascript(t('.search.noresult'))}', - searchingText: '#{escape_javascript(t('.search.placeholder'))}', - theme: 'facebook' - }); - }); - -- content_for :sidebar do - = render "shared/workgroup_members" - -= simple_form_for @task do |f| - = f.hidden_field :current_user_id - = f.input :name - = f.input :description, as: :text, input_html: {rows: 10} - = f.input :duration, :as => :select, :collection => 1..3 - = f.input :user_list, :as => :string, :input_html => { 'data-pre' => @task.users.map(&:token_attributes).to_json } - = f.input :required_users - = f.association :workgroup - = f.input :due_date, as: :date_picker - = f.input :done - .form-actions - = f.submit class: 'btn btn-primary' - - if @task.new_record? or @task.periodic? - = f.submit t('.submit.periodic'), name: 'periodic', class: 'btn' - = link_to t('ui.or_cancel'), :back += form.hidden_field :current_user_id += form.input :name += form.input :description, as: :text, input_html: {rows: 10} += form.input :duration, :as => :select, :collection => 1..3 +- unless local_assigns[:periodic] + = form.input :user_list, :as => :string, :input_html => { 'data-pre' => form.object.users.map(&:token_attributes).to_json } += form.input :required_users += form.association :workgroup += form.input :due_date, as: :date_picker +- unless local_assigns[:periodic] + = form.input :done diff --git a/app/views/tasks/_form_sidebar.html.haml b/app/views/tasks/_form_sidebar.html.haml new file mode 100644 index 00000000..c32a6c94 --- /dev/null +++ b/app/views/tasks/_form_sidebar.html.haml @@ -0,0 +1,15 @@ +- content_for :javascript do + :javascript + $(function() { + $("#task_user_list").tokenInput("#{users_path(:format => :json)}", { + crossDomain: false, + prePopulate: $("#task_user_list").data("pre"), + hintText: '#{escape_javascript(t('.search.hint'))}', + noResultText: '#{escape_javascript(t('.search.noresult'))}', + searchingText: '#{escape_javascript(t('.search.placeholder'))}', + theme: 'facebook' + }); + }); + +- content_for :sidebar do + = render "shared/workgroup_members" diff --git a/app/views/tasks/edit.haml b/app/views/tasks/edit.haml index 624324db..35cd9cb5 100644 --- a/app/views/tasks/edit.haml +++ b/app/views/tasks/edit.haml @@ -1,3 +1,15 @@ -- title t('.title') +- title @periodic ? t('.title_periodic') : t('.title') -= render 'form' +- if @task.periodic? && !@periodic + .alert.alert-info= raw t('tasks.edit.warning_periodic') + += render 'form_sidebar' + += simple_form_for @task do |form| + = render 'form', form: form, periodic: @periodic + .form-actions + - if @periodic + = form.submit t('.submit_periodic'), name: 'periodic', class: 'btn btn-primary' + - else + = form.submit class: 'btn btn-primary' + = link_to t('ui.or_cancel'), :back diff --git a/app/views/tasks/new.haml b/app/views/tasks/new.haml index 624324db..277480cf 100644 --- a/app/views/tasks/new.haml +++ b/app/views/tasks/new.haml @@ -1,3 +1,10 @@ - title t('.title') -= render 'form' += render 'form_sidebar' + += simple_form_for @task do |form| + = render 'form', form: form, periodic: nil + .form-actions + = form.submit class: 'btn btn-primary' + = form.submit t('.submit_periodic'), name: 'periodic', class: 'btn' + = link_to t('ui.or_cancel'), :back diff --git a/app/views/tasks/show.haml b/app/views/tasks/show.haml index 93f61269..ba7a36d0 100644 --- a/app/views/tasks/show.haml +++ b/app/views/tasks/show.haml @@ -10,7 +10,7 @@ %dd= simple_format(@task.description) - if @task.due_date.present? %dt= heading_helper Task, :due_date - %dd + %dd = format_date(@task.due_date) - if @task.periodic? %i.icon-repeat{title: t('tasks.repeated')} @@ -30,8 +30,14 @@ - unless @task.done? = link_to t('.mark_done'), set_done_task_path(@task), method: :post, class: 'btn' = link_to t('ui.edit'), edit_task_path(@task), class: 'btn' - = link_to t('ui.delete'), task_path(@task), :method => :delete, :data => {:confirm => t('.confirm_delete_single')}, - class: 'btn btn-danger' - if @task.periodic? - = link_to t('.delete_group'), task_path(@task, periodic: true), method: :delete, - :data => {confirm: t('.confirm_delete_group')}, class: 'btn btn-danger' + = link_to edit_task_path(@task, periodic: true), class: 'btn' do + %i.icon.icon-repeat + = t('.edit_group') + = link_to t('ui.delete'), task_path(@task), method: :delete, class: 'btn btn-danger', + data: {confirm: @task.periodic? ? t('.confirm_delete_single_from_group') : t('.confirm_delete_single')} + - if @task.periodic? + = link_to task_path(@task, periodic: true), method: :delete, class: 'btn btn-danger', + data: {confirm: t('.confirm_delete_group')} do + %i.icon.icon-repeat + = t('.delete_group') diff --git a/config/locales/en.yml b/config/locales/en.yml index efbc19b2..a783a8d2 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1624,6 +1624,8 @@ en: notice: Task has been deleted edit: title: Edit task + title_periodic: Edit periodic task + submit_periodic: Save periodic task warning_periodic: "Warning: This task is part of a group of weekly tasks. When saving it will be excluded from the group and it will be converted to a regular task." error_not_found: No workgroup found form: @@ -1631,8 +1633,6 @@ en: hint: Search for user noresult: No user found placeholder: Search ... - submit: - periodic: Save weekly task index: show_group_tasks: Show group tasks title: Tasks @@ -1653,7 +1653,8 @@ en: new_task: Create new task pages: Pages new: - title: Create new tasks + title: Create new task + submit_periodic: Create periodic task repeated: Task is repeated weekly set_done: notice: The state of the task has been updated @@ -1661,7 +1662,9 @@ en: accept_task: Accept task confirm_delete_group: Really delete this and all subsequent tasks? confirm_delete_single: Are you sure you want to delete the task? + confirm_delete_single_from_group: Are you sure you want to delete this task (and keep related periodic tasks)? delete_group: Delete task and subsequent + edit_group: Edit periodic hours: "%{count}h" mark_done: Mark task as done reject_task: Reject task