Add filters by project, author, type, and action to task queue page list
This commit is contained in:
parent
c4c4b808f3
commit
07eb334c25
|
@ -1,12 +1,6 @@
|
||||||
class Dashboard::TasksController < Dashboard::ApplicationController
|
class Dashboard::TasksController < Dashboard::ApplicationController
|
||||||
def index
|
def index
|
||||||
@tasks = case params[:state]
|
@tasks = TasksFinder.new(current_user, params).execute
|
||||||
when 'done'
|
|
||||||
current_user.tasks.done
|
|
||||||
else
|
|
||||||
current_user.tasks.pending
|
|
||||||
end
|
|
||||||
|
|
||||||
@tasks = @tasks.page(params[:page]).per(PER_PAGE)
|
@tasks = @tasks.page(params[:page]).per(PER_PAGE)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -38,4 +38,37 @@ module TasksHelper
|
||||||
text = first_line_in_markdown(text, 150, options)
|
text = first_line_in_markdown(text, 150, options)
|
||||||
sanitize(text, tags: %w(a img b pre code p span))
|
sanitize(text, tags: %w(a img b pre code p span))
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -3,12 +3,37 @@
|
||||||
|
|
||||||
.top-area
|
.top-area
|
||||||
%ul.nav-links
|
%ul.nav-links
|
||||||
%li{class: ("active" if params[:state].blank? || params[:state] == 'pending')}
|
%li{class: ('active' if params[:state].blank? || params[:state] == 'pending')}
|
||||||
= link_to dashboard_tasks_path(state: 'pending') do
|
= link_to page_filter_path(state: 'pending') do
|
||||||
Tasks (#{tasks_pending_count})
|
%span
|
||||||
%li{class: ("active" if params[:state] == 'done')}
|
Tasks
|
||||||
= link_to dashboard_tasks_path(state: 'done') do
|
%span{class: 'badge'}
|
||||||
Done (#{tasks_done_count})
|
= 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
|
.tasks
|
||||||
- if @tasks.any?
|
- if @tasks.any?
|
||||||
|
@ -23,3 +48,11 @@
|
||||||
= paginate @tasks, theme: "gitlab"
|
= paginate @tasks, theme: "gitlab"
|
||||||
- else
|
- else
|
||||||
.nothing-here-block No tasks to show
|
.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());
|
||||||
|
});
|
||||||
|
|
|
@ -4,6 +4,9 @@ Feature: Dashboard Task Queue
|
||||||
Given I sign in as a user
|
Given I sign in as a user
|
||||||
And I own project "Shop"
|
And I own project "Shop"
|
||||||
And "John Doe" is a developer of 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 have pending tasks
|
||||||
And I visit dashboard task queue page
|
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 mark the pending task as done
|
||||||
And I click on the "Done" tab
|
And I click on the "Done" tab
|
||||||
Then I should see all tasks marked as done
|
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
|
||||||
|
|
|
@ -3,58 +3,126 @@ class Spinach::Features::DashboardTaskQueue < Spinach::FeatureSteps
|
||||||
include SharedPaths
|
include SharedPaths
|
||||||
include SharedProject
|
include SharedProject
|
||||||
include SharedUser
|
include SharedUser
|
||||||
|
include Select2Helper
|
||||||
|
|
||||||
step '"John Doe" is a developer of project "Shop"' do
|
step '"John Doe" is a developer of project "Shop"' do
|
||||||
project.team << [john_doe, :developer]
|
project.team << [john_doe, :developer]
|
||||||
end
|
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
|
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
|
end
|
||||||
|
|
||||||
step 'I should see pending tasks assigned to me' do
|
step 'I should see pending tasks assigned to me' do
|
||||||
expect(page).to have_link 'Tasks (1)'
|
expect(page).to have_content 'Tasks 4'
|
||||||
expect(page).to have_link 'Done (0)'
|
expect(page).to have_content 'Done 0'
|
||||||
|
|
||||||
page.within('.tasks') do
|
expect(page).to have_link project.name_with_namespace
|
||||||
expect(page).to have_content project.name_with_namespace
|
should_see_task(1, "John Doe assigned merge request ##{merge_request.iid}", merge_request.title)
|
||||||
expect(page).to have_content "John Doe assigned issue ##{assigned_issue.iid}"
|
should_see_task(2, "John Doe mentioned on issue ##{issue.iid}", "#{current_user.to_reference} Wdyt?")
|
||||||
expect(page).to have_content(assigned_issue.title[0..10])
|
should_see_task(3, "John Doe assigned issue ##{issue.iid}", issue.title)
|
||||||
expect(page).to have_link 'Done'
|
should_see_task(4, "Mary Jane mentioned on issue ##{issue.iid}", issue.title)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
step 'I mark the pending task as done' do
|
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_content 'Task was successfully marked as done.'
|
||||||
expect(page).to have_link 'Tasks (0)'
|
expect(page).to have_content 'Tasks 3'
|
||||||
expect(page).to have_link 'Done (1)'
|
expect(page).to have_content 'Done 1'
|
||||||
expect(page).to have_content 'No tasks to show'
|
should_not_see_task "John Doe assigned merge request ##{merge_request.iid}"
|
||||||
end
|
end
|
||||||
|
|
||||||
step 'I click on the "Done" tab' do
|
step 'I click on the "Done" tab' do
|
||||||
click_link 'Done (1)'
|
click_link 'Done 1'
|
||||||
end
|
end
|
||||||
|
|
||||||
step 'I should see all tasks marked as done' do
|
step 'I should see all tasks marked as done' do
|
||||||
page.within('.tasks') do
|
expect(page).to have_link project.name_with_namespace
|
||||||
expect(page).to have_content project.name_with_namespace
|
should_see_task(1, "John Doe assigned merge request ##{merge_request.iid}", merge_request.title, false)
|
||||||
expect(page).to have_content "John Doe assigned issue ##{assigned_issue.iid}"
|
end
|
||||||
expect(page).to have_content(assigned_issue.title[0..10])
|
|
||||||
expect(page).not_to have_link 'Done'
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
def assigned_issue
|
def should_not_see_task(title)
|
||||||
@assigned_issue ||= create(:issue, assignee: current_user, project: project)
|
expect(page).not_to have_content title
|
||||||
end
|
end
|
||||||
|
|
||||||
def john_doe
|
def john_doe
|
||||||
@john_doe ||= user_exists("John Doe", { username: "john_doe" })
|
@john_doe ||= user_exists("John Doe", { username: "john_doe" })
|
||||||
end
|
end
|
||||||
|
|
||||||
def project
|
def mary_jane
|
||||||
@project ||= create(:project, name: "Shop")
|
@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
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue