From 07eb334c2546294acea43e85308bec907b13467c Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Thu, 18 Feb 2016 01:20:31 -0200 Subject: [PATCH] Add filters by project, author, type, and action to task queue page list --- app/controllers/dashboard/tasks_controller.rb | 8 +- app/finders/tasks_finder.rb | 129 ++++++++++++++++++ app/helpers/tasks_helper.rb | 33 +++++ app/views/dashboard/tasks/index.html.haml | 45 +++++- features/dashboard/task_queue.feature | 23 ++++ features/steps/dashboard/task_queue.rb | 114 ++++++++++++---- 6 files changed, 316 insertions(+), 36 deletions(-) create mode 100644 app/finders/tasks_finder.rb diff --git a/app/controllers/dashboard/tasks_controller.rb b/app/controllers/dashboard/tasks_controller.rb index e3245609204..a8884be54e4 100644 --- a/app/controllers/dashboard/tasks_controller.rb +++ b/app/controllers/dashboard/tasks_controller.rb @@ -1,12 +1,6 @@ class Dashboard::TasksController < Dashboard::ApplicationController def index - @tasks = case params[:state] - when 'done' - current_user.tasks.done - else - current_user.tasks.pending - end - + @tasks = TasksFinder.new(current_user, params).execute @tasks = @tasks.page(params[:page]).per(PER_PAGE) end diff --git a/app/finders/tasks_finder.rb b/app/finders/tasks_finder.rb new file mode 100644 index 00000000000..2a32e977c24 --- /dev/null +++ b/app/finders/tasks_finder.rb @@ -0,0 +1,129 @@ +# TasksFinder +# +# Used to filter Tasks by set of params +# +# Arguments: +# current_user - which user use +# params: +# action_id: integer +# author_id: integer +# project_id; integer +# state: 'pending' or 'done' +# type: 'Issue' or 'MergeRequest' +# + +class TasksFinder + NONE = '0' + + attr_accessor :current_user, :params + + def initialize(current_user, params) + @current_user = current_user + @params = params + end + + def execute + items = current_user.tasks + items = by_action_id(items) + items = by_author(items) + items = by_project(items) + items = by_state(items) + items = by_type(items) + + items + end + + private + + def action_id? + action_id.present? && [Task::ASSIGNED, Task::MENTIONED].include?(action_id.to_i) + end + + def action_id + params[:action_id] + end + + def author? + params[:author_id].present? + end + + def author + return @author if defined?(@author) + + @author = + if author? && params[:author_id] != NONE + User.find(params[:author_id]) + else + nil + end + end + + def project? + params[:project_id].present? + end + + def project + return @project if defined?(@project) + + if project? + @project = Project.find(params[:project_id]) + + unless Ability.abilities.allowed?(current_user, :read_project, @project) + @project = nil + end + else + @project = nil + end + + @project + end + + def type? + type.present? && ['Issue', 'MergeRequest'].include?(type) + end + + def type + params[:type] + end + + def by_action_id(items) + if action_id? + items = items.where(action: action_id) + end + + items + end + + def by_author(items) + if author? + items = items.where(author_id: author.try(:id)) + end + + items + end + + def by_project(items) + if project? + items = items.where(project: project) + end + + items + end + + def by_state(items) + case params[:state] + when 'done' + items.done + else + items.pending + end + end + + def by_type(items) + if type? + items = items.where(target_type: type) + end + + items + end +end diff --git a/app/helpers/tasks_helper.rb b/app/helpers/tasks_helper.rb index 6975c1d1604..59c7d93e65e 100644 --- a/app/helpers/tasks_helper.rb +++ b/app/helpers/tasks_helper.rb @@ -38,4 +38,37 @@ module TasksHelper text = first_line_in_markdown(text, 150, options) sanitize(text, tags: %w(a img b pre code p span)) end + + def task_actions_options + actions = [ + OpenStruct.new(id: '', title: 'Any Action'), + OpenStruct.new(id: Task::ASSIGNED, title: 'Assigned'), + OpenStruct.new(id: Task::MENTIONED, title: 'Mentioned') + ] + + options_from_collection_for_select(actions, 'id', 'title', params[:action_id]) + end + + def task_projects_options + projects = current_user.authorized_projects.sorted_by_activity.non_archived + projects = projects.includes(:namespace) + + projects = projects.map do |project| + OpenStruct.new(id: project.id, title: project.name_with_namespace) + end + + projects.unshift(OpenStruct.new(id: '', title: 'Any Project')) + + options_from_collection_for_select(projects, 'id', 'title', params[:project_id]) + end + + def task_types_options + types = [ + OpenStruct.new(title: 'Any Type', name: ''), + OpenStruct.new(title: 'Issue', name: 'Issue'), + OpenStruct.new(title: 'Merge Request', name: 'MergeRequest') + ] + + options_from_collection_for_select(types, 'name', 'title', params[:type]) + end end diff --git a/app/views/dashboard/tasks/index.html.haml b/app/views/dashboard/tasks/index.html.haml index 2f582009288..16e7b4ae0c5 100644 --- a/app/views/dashboard/tasks/index.html.haml +++ b/app/views/dashboard/tasks/index.html.haml @@ -3,12 +3,37 @@ .top-area %ul.nav-links - %li{class: ("active" if params[:state].blank? || params[:state] == 'pending')} - = link_to dashboard_tasks_path(state: 'pending') do - Tasks (#{tasks_pending_count}) - %li{class: ("active" if params[:state] == 'done')} - = link_to dashboard_tasks_path(state: 'done') do - Done (#{tasks_done_count}) + %li{class: ('active' if params[:state].blank? || params[:state] == 'pending')} + = link_to page_filter_path(state: 'pending') do + %span + Tasks + %span{class: 'badge'} + = tasks_pending_count + %li{class: ('active' if params[:state] == 'done')} + = link_to page_filter_path(state: 'done') do + %span + Done + %span{class: 'badge'} + = tasks_done_count + +.tasks-filters + .gray-content-block.second-block + = form_tag page_filter_path(without: [:assignee_id, :milestone_title, :label_name, :scope, :sort]), method: :get, class: 'filter-form' do + .filter-item.inline + = select_tag('project_id', task_projects_options, + class: 'select2 trigger-submit', include_blank: true, + data: {placeholder: 'Project'}) + .filter-item.inline + = users_select_tag(:author_id, selected: params[:author_id], + placeholder: 'Author', class: 'trigger-submit', any_user: "Any Author", first_user: true, current_user: true) + .filter-item.inline + = select_tag('type', task_types_options, + class: 'select2 trigger-submit', include_blank: true, + data: {placeholder: 'Type'}) + .filter-item.inline.actions-filter + = select_tag('action_id', task_actions_options, + class: 'select2 trigger-submit', include_blank: true, + data: {placeholder: 'Action'}) .tasks - if @tasks.any? @@ -23,3 +48,11 @@ = paginate @tasks, theme: "gitlab" - else .nothing-here-block No tasks to show + +:javascript + new UsersSelect(); + + $('form.filter-form').on('submit', function (event) { + event.preventDefault(); + Turbolinks.visit(this.action + '&' + $(this).serialize()); + }); diff --git a/features/dashboard/task_queue.feature b/features/dashboard/task_queue.feature index 42b4a86e498..8972a148289 100644 --- a/features/dashboard/task_queue.feature +++ b/features/dashboard/task_queue.feature @@ -4,6 +4,9 @@ Feature: Dashboard Task Queue Given I sign in as a user And I own project "Shop" And "John Doe" is a developer of project "Shop" + And "Mary Jane" is a developer of project "Shop" + And "Mary Jane" owns private project "Enterprise" + And I am a developer of project "Enterprise" And I have pending tasks And I visit dashboard task queue page @@ -13,3 +16,23 @@ Feature: Dashboard Task Queue And I mark the pending task as done And I click on the "Done" tab Then I should see all tasks marked as done + + @javascript + Scenario: I filter by project + Given I filter by "Enterprise" + Then I should not see tasks + + @javascript + Scenario: I filter by author + Given I filter by "John Doe" + Then I should not see tasks related to "Mary Jane" in the list + + @javascript + Scenario: I filter by type + Given I filter by "Issue" + Then I should not see tasks related to "Merge Requests" in the list + + @javascript + Scenario: I filter by action + Given I filter by "Mentioned" + Then I should not see tasks related to "Assignments" in the list diff --git a/features/steps/dashboard/task_queue.rb b/features/steps/dashboard/task_queue.rb index 8695dd5cfb1..53920f585dc 100644 --- a/features/steps/dashboard/task_queue.rb +++ b/features/steps/dashboard/task_queue.rb @@ -3,58 +3,126 @@ class Spinach::Features::DashboardTaskQueue < Spinach::FeatureSteps include SharedPaths include SharedProject include SharedUser + include Select2Helper step '"John Doe" is a developer of project "Shop"' do project.team << [john_doe, :developer] end + step 'I am a developer of project "Enterprise"' do + enterprise.team << [current_user, :developer] + end + + step '"Mary Jane" is a developer of project "Shop"' do + project.team << [john_doe, :developer] + end + step 'I have pending tasks' do - create(:task, user: current_user, project: project, author: john_doe, target: assigned_issue, action: Task::ASSIGNED) + create(:task, user: current_user, project: project, author: mary_jane, target: issue, action: Task::MENTIONED) + create(:task, user: current_user, project: project, author: john_doe, target: issue, action: Task::ASSIGNED) + note = create(:note, author: john_doe, noteable: issue, note: "#{current_user.to_reference} Wdyt?") + create(:task, user: current_user, project: project, author: john_doe, target: issue, action: Task::MENTIONED, note: note) + create(:task, user: current_user, project: project, author: john_doe, target: merge_request, action: Task::ASSIGNED) end step 'I should see pending tasks assigned to me' do - expect(page).to have_link 'Tasks (1)' - expect(page).to have_link 'Done (0)' + expect(page).to have_content 'Tasks 4' + expect(page).to have_content 'Done 0' - page.within('.tasks') do - expect(page).to have_content project.name_with_namespace - expect(page).to have_content "John Doe assigned issue ##{assigned_issue.iid}" - expect(page).to have_content(assigned_issue.title[0..10]) - expect(page).to have_link 'Done' - end + expect(page).to have_link project.name_with_namespace + should_see_task(1, "John Doe assigned merge request ##{merge_request.iid}", merge_request.title) + should_see_task(2, "John Doe mentioned on issue ##{issue.iid}", "#{current_user.to_reference} Wdyt?") + should_see_task(3, "John Doe assigned issue ##{issue.iid}", issue.title) + should_see_task(4, "Mary Jane mentioned on issue ##{issue.iid}", issue.title) end step 'I mark the pending task as done' do - click_link 'Done' + page.within('.task:nth-child(1)') do + click_link 'Done' + end expect(page).to have_content 'Task was successfully marked as done.' - expect(page).to have_link 'Tasks (0)' - expect(page).to have_link 'Done (1)' - expect(page).to have_content 'No tasks to show' + expect(page).to have_content 'Tasks 3' + expect(page).to have_content 'Done 1' + should_not_see_task "John Doe assigned merge request ##{merge_request.iid}" end step 'I click on the "Done" tab' do - click_link 'Done (1)' + click_link 'Done 1' end step 'I should see all tasks marked as done' do - page.within('.tasks') do - expect(page).to have_content project.name_with_namespace - expect(page).to have_content "John Doe assigned issue ##{assigned_issue.iid}" - expect(page).to have_content(assigned_issue.title[0..10]) - expect(page).not_to have_link 'Done' + expect(page).to have_link project.name_with_namespace + should_see_task(1, "John Doe assigned merge request ##{merge_request.iid}", merge_request.title, false) + end + + step 'I filter by "Enterprise"' do + select2(enterprise.id, from: "#project_id") + end + + step 'I filter by "John Doe"' do + select2(john_doe.id, from: "#author_id") + end + + step 'I filter by "Issue"' do + select2('Issue', from: "#type") + end + + step 'I filter by "Mentioned"' do + select2("#{Task::MENTIONED}", from: '#action_id') + end + + step 'I should not see tasks' do + expect(page).to have_content 'No tasks to show' + end + + step 'I should not see tasks related to "Mary Jane" in the list' do + should_not_see_task "Mary Jane mentioned on issue ##{issue.iid}" + end + + step 'I should not see tasks related to "Merge Requests" in the list' do + should_not_see_task "John Doe assigned merge request ##{merge_request.iid}" + end + + step 'I should not see tasks related to "Assignments" in the list' do + should_not_see_task "John Doe assigned merge request ##{merge_request.iid}" + should_not_see_task "John Doe assigned issue ##{issue.iid}" + end + + def should_see_task(position, title, body, pending = true) + page.within(".task:nth-child(#{position})") do + expect(page).to have_content title + expect(page).to have_content body + + if pending + expect(page).to have_link 'Done' + else + expect(page).to_not have_link 'Done' + end end end - def assigned_issue - @assigned_issue ||= create(:issue, assignee: current_user, project: project) + def should_not_see_task(title) + expect(page).not_to have_content title end def john_doe @john_doe ||= user_exists("John Doe", { username: "john_doe" }) end - def project - @project ||= create(:project, name: "Shop") + def mary_jane + @mary_jane ||= user_exists("Mary Jane", { username: "mary_jane" }) + end + + def enterprise + @enterprise ||= Project.find_by(name: 'Enterprise') + end + + def issue + @issue ||= create(:issue, assignee: current_user, project: project) + end + + def merge_request + @merge_request ||= create(:merge_request, assignee: current_user, source_project: project) end end