Rename Tasks to Todos

parent 408e010d
......@@ -65,7 +65,7 @@ v 8.5.0 (unreleased)
- Fix broken link to project in build notification emails
- Ability to see and sort on vote count from Issues and MR lists
- Fix builds scheduler when first build in stage was allowed to fail
- User project limit is reached notice is hidden if the projects limit is zero
- User project limit is reached notice is hidden if the projects limit is zero
- Add API support for managing runners and project's runners
- Allow SAML users to login with no previous account without having to allow
all Omniauth providers to do so.
......@@ -75,7 +75,7 @@ v 8.5.0 (unreleased)
- Emoji comment on diffs are not award emoji
- Add label description (Nuttanart Pornprasitsakul)
- Show label row when filtering issues or merge requests by label (Nuttanart Pornprasitsakul)
- Add Task Queue
- Add Todos
v 8.4.4
- Update omniauth-saml gem to 1.4.2
......
/**
* Dashboard tasks queue
* Dashboard Todos
*
*/
.navbar-nav {
li {
.badge.tasks-pending-count {
.badge.todos-pending-count {
background-color: #7f8fa4;
margin-top: -5px;
}
}
}
.tasks {
.todos {
.panel {
border-top: none;
margin-bottom: 0;
}
}
.task-item {
.todo-item {
font-size: $gl-font-size;
padding: $gl-padding-top 0 $gl-padding-top ($gl-avatar-size + $gl-padding-top);
border-bottom: 1px solid $table-border-color;
color: #7f8fa4;
&.task-inline {
&.todo-inline {
.avatar {
position: relative;
top: -2px;
}
.task-title {
.todo-title {
line-height: 40px;
}
}
......@@ -44,7 +44,7 @@
margin-left: -($gl-avatar-size + $gl-padding-top);
}
.task-title {
.todo-title {
@include str-truncated(calc(100% - 174px));
font-weight: 600;
......@@ -53,10 +53,10 @@
}
}
.task-body {
.todo-body {
margin-right: 174px;
.task-note {
.todo-note {
word-wrap: break-word;
.md {
......@@ -89,7 +89,7 @@
}
}
.task-note-icon {
.todo-note-icon {
color: #777;
float: left;
font-size: $gl-font-size;
......@@ -102,10 +102,10 @@
}
@media (max-width: $screen-xs-max) {
.task-item {
.todo-item {
padding-left: $gl-padding;
.task-title {
.todo-title {
white-space: normal;
overflow: visible;
max-width: 100%;
......@@ -115,7 +115,7 @@
display: none;
}
.task-body {
.todo-body {
margin: 0;
border-left: 2px solid #DDD;
padding-left: 10px;
......
class Dashboard::TasksController < Dashboard::ApplicationController
def index
@tasks = TasksFinder.new(current_user, params).execute
@tasks = @tasks.page(params[:page]).per(PER_PAGE)
end
def destroy
task.done!
respond_to do |format|
format.html { redirect_to dashboard_tasks_path, notice: 'Task was successfully marked as done.' }
format.js { render nothing: true }
end
end
private
def task
@task ||= current_user.tasks.find(params[:id])
end
end
class Dashboard::TodosController < Dashboard::ApplicationController
def index
@todos = TodosFinder.new(current_user, params).execute
@todos = @todos.page(params[:page]).per(PER_PAGE)
end
def destroy
todo.done!
respond_to do |format|
format.html { redirect_to dashboard_todos_path, notice: 'Todo was successfully marked as done.' }
format.js { render nothing: true }
end
end
private
def todo
@todo ||= current_user.todos.find(params[:id])
end
end
......@@ -181,7 +181,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
return
end
TaskService.new.merge_merge_request(merge_request, current_user)
TodoService.new.merge_merge_request(merge_request, current_user)
@merge_request.update(merge_error: nil)
......
# TasksFinder
# TodosFinder
#
# Used to filter Tasks by set of params
# Used to filter Todos by set of params
#
# Arguments:
# current_user - which user use
......@@ -12,7 +12,7 @@
# type: 'Issue' or 'MergeRequest'
#
class TasksFinder
class TodosFinder
NONE = '0'
attr_accessor :current_user, :params
......@@ -23,7 +23,7 @@ class TasksFinder
end
def execute
items = current_user.tasks
items = current_user.todos
items = by_action_id(items)
items = by_author(items)
items = by_project(items)
......@@ -36,7 +36,7 @@ class TasksFinder
private
def action_id?
action_id.present? && [Task::ASSIGNED, Task::MENTIONED].include?(action_id.to_i)
action_id.present? && [Todo::ASSIGNED, Todo::MENTIONED].include?(action_id.to_i)
end
def action_id
......
module TasksHelper
def link_to_author(task)
author = task.author
if author
link_to author.name, user_path(author.username)
else
task.author_name
end
end
def tasks_pending_count
current_user.tasks.pending.count
module TodosHelper
def todos_pending_count
current_user.todos.pending.count
end
def tasks_done_count
current_user.tasks.done.count
def todos_done_count
current_user.todos.done.count
end
def task_action_name(task)
target = task.target_type.titleize.downcase
def todo_action_name(todo)
target = todo.target_type.titleize.downcase
[task.action_name, target].join(" ")
[todo.action_name, target].join(" ")
end
def task_target_link_html(task)
link_to "##{task.target_iid}", task_target_path(task)
def todo_target_link_html(todo)
link_to "##{todo.target_iid}", todo_target_path(todo)
end
def task_target_path(task)
anchor = dom_id(task.note) if task.note.present?
def todo_target_path(todo)
anchor = dom_id(todo.note) if todo.note.present?
polymorphic_path([task.project.namespace.becomes(Namespace),
task.project, task.target], anchor: anchor)
polymorphic_path([todo.project.namespace.becomes(Namespace),
todo.project, todo.target], anchor: anchor)
end
def task_actions_options
def todo_actions_options
actions = [
OpenStruct.new(id: '', title: 'Any Action'),
OpenStruct.new(id: Task::ASSIGNED, title: 'Assigned'),
OpenStruct.new(id: Task::MENTIONED, title: 'Mentioned')
OpenStruct.new(id: Todo::ASSIGNED, title: 'Assigned'),
OpenStruct.new(id: Todo::MENTIONED, title: 'Mentioned')
]
options_from_collection_for_select(actions, 'id', 'title', params[:action_id])
end
def task_projects_options
def todo_projects_options
projects = current_user.authorized_projects.sorted_by_activity.non_archived
projects = projects.includes(:namespace)
......@@ -57,7 +47,7 @@ module TasksHelper
options_from_collection_for_select(projects, 'id', 'title', params[:project_id])
end
def task_types_options
def todo_types_options
types = [
OpenStruct.new(title: 'Any Type', name: ''),
OpenStruct.new(title: 'Issue', name: 'Issue'),
......
......@@ -37,7 +37,7 @@ class Note < ActiveRecord::Base
belongs_to :author, class_name: "User"
belongs_to :updated_by, class_name: "User"
has_many :tasks, dependent: :destroy
has_many :todos, dependent: :destroy
delegate :name, to: :project, prefix: true
delegate :name, :email, to: :author, prefix: true
......
# == Schema Information
#
# Table name: tasks
# Table name: todos
#
# id :integer not null, primary key
# user_id :integer not null
......@@ -15,7 +15,7 @@
# updated_at :datetime
#
class Task < ActiveRecord::Base
class Todo < ActiveRecord::Base
ASSIGNED = 1
MENTIONED = 2
......
......@@ -140,7 +140,7 @@ class User < ActiveRecord::Base
has_one :abuse_report, dependent: :destroy
has_many :spam_logs, dependent: :destroy
has_many :builds, dependent: :nullify, class_name: 'Ci::Build'
has_many :tasks, dependent: :destroy
has_many :todos, dependent: :destroy
#
# Validations
......
......@@ -23,8 +23,8 @@ class BaseService
EventCreateService.new
end
def task_service
TaskService.new
def todo_service
TodoService.new
end
def log_info(message)
......
......@@ -3,7 +3,7 @@ module Issues
def execute(issue, commit = nil)
if project.jira_tracker? && project.jira_service.active
project.jira_service.execute(commit, issue)
task_service.close_issue(issue, current_user)
todo_service.close_issue(issue, current_user)
return issue
end
......@@ -11,7 +11,7 @@ module Issues
event_service.close_issue(issue, current_user)
create_note(issue, commit)
notification_service.close_issue(issue, current_user)
task_service.close_issue(issue, current_user)
todo_service.close_issue(issue, current_user)
execute_hooks(issue, 'close')
end
......
......@@ -9,7 +9,7 @@ module Issues
if issue.save
issue.update_attributes(label_ids: label_params)
notification_service.new_issue(issue, current_user)
task_service.new_issue(issue, current_user)
todo_service.new_issue(issue, current_user)
event_service.open_issue(issue, current_user)
issue.create_cross_references!(current_user)
execute_hooks(issue, 'open')
......
......@@ -6,12 +6,12 @@ module Issues
def handle_changes(issue, options = {})
if has_changes?(issue, options)
task_service.mark_pending_tasks_as_done(issue, current_user)
todo_service.mark_pending_todos_as_done(issue, current_user)
end
if issue.previous_changes.include?('title') ||
issue.previous_changes.include?('description')
task_service.update_issue(issue, current_user)
todo_service.update_issue(issue, current_user)
end
if issue.previous_changes.include?('milestone_id')
......@@ -21,7 +21,7 @@ module Issues
if issue.previous_changes.include?('assignee_id')
create_assignee_note(issue)
notification_service.reassigned_issue(issue, current_user)
task_service.reassigned_issue(issue, current_user)
todo_service.reassigned_issue(issue, current_user)
end
end
......
......@@ -9,7 +9,7 @@ module MergeRequests
event_service.close_mr(merge_request, current_user)
create_note(merge_request)
notification_service.close_mr(merge_request, current_user)
task_service.close_merge_request(merge_request, current_user)
todo_service.close_merge_request(merge_request, current_user)
execute_hooks(merge_request, 'close')
end
......
......@@ -18,7 +18,7 @@ module MergeRequests
merge_request.update_attributes(label_ids: label_params)
event_service.open_mr(merge_request, current_user)
notification_service.new_merge_request(merge_request, current_user)
task_service.new_merge_request(merge_request, current_user)
todo_service.new_merge_request(merge_request, current_user)
merge_request.create_cross_references!(current_user)
execute_hooks(merge_request)
end
......
......@@ -16,12 +16,12 @@ module MergeRequests
def handle_changes(merge_request, options = {})
if has_changes?(merge_request, options)
task_service.mark_pending_tasks_as_done(merge_request, current_user)
todo_service.mark_pending_todos_as_done(merge_request, current_user)
end
if merge_request.previous_changes.include?('title') ||
merge_request.previous_changes.include?('description')
task_service.update_merge_request(merge_request, current_user)
todo_service.update_merge_request(merge_request, current_user)
end
if merge_request.previous_changes.include?('target_branch')
......@@ -37,7 +37,7 @@ module MergeRequests
if merge_request.previous_changes.include?('assignee_id')
create_assignee_note(merge_request)
notification_service.reassigned_merge_request(merge_request, current_user)
task_service.reassigned_merge_request(merge_request, current_user)
todo_service.reassigned_merge_request(merge_request, current_user)
end
if merge_request.previous_changes.include?('target_branch') ||
......
......@@ -8,7 +8,7 @@ module Notes
if note.save
# Finish the harder work in the background
NewNoteWorker.perform_in(2.seconds, note.id, params)
TaskService.new.new_note(note, current_user)
TodoService.new.new_note(note, current_user)
end
note
......
......@@ -8,7 +8,7 @@ module Notes
note.reset_events_cache
if note.previous_changes.include?('note')
TaskService.new.update_note(note, current_user)
TodoService.new.update_note(note, current_user)
end
note
......
# TaskService class
# TodoService class
#
# Used for creating tasks on task queue after certain user action
# Used for creating todos after certain user actions
#
# Ex.
# TaskService.new.new_issue(issue, current_user)
# TodoService.new.new_issue(issue, current_user)
#
class TaskService
class TodoService
# When create an issue we should:
#
# * create a task for assignee if issue is assigned
# * create a task for each mentioned user on issue
# * create a todo for assignee if issue is assigned
# * create a todo for each mentioned user on issue
#
def new_issue(issue, current_user)
new_issuable(issue, current_user)
......@@ -17,32 +17,32 @@ class TaskService
# When update an issue we should:
#
# * mark all pending tasks related to the issue for the current user as done
# * mark all pending todos related to the issue for the current user as done
#
def update_issue(issue, current_user)
create_mention_tasks(issue.project, issue, current_user)
create_mention_todos(issue.project, issue, current_user)
end
# When close an issue we should:
#
# * mark all pending tasks related to the target for the current user as done
# * mark all pending todos related to the target for the current user as done
#
def close_issue(issue, current_user)
mark_pending_tasks_as_done(issue, current_user)
mark_pending_todos_as_done(issue, current_user)
end
# When we reassign an issue we should:
#
# * create a pending task for new assignee if issue is assigned
# * create a pending todo for new assignee if issue is assigned
#
def reassigned_issue(issue, current_user)
create_assignment_task(issue, current_user)
create_assignment_todo(issue, current_user)
end
# When create a merge request we should:
#
# * creates a pending task for assignee if merge request is assigned
# * create a task for each mentioned user on merge request
# * creates a pending todo for assignee if merge request is assigned
# * create a todo for each mentioned user on merge request
#
def new_merge_request(merge_request, current_user)
new_issuable(merge_request, current_user)
......@@ -50,40 +50,40 @@ class TaskService
# When update a merge request we should:
#
# * create a task for each mentioned user on merge request
# * create a todo for each mentioned user on merge request
#
def update_merge_request(merge_request, current_user)
create_mention_tasks(merge_request.project, merge_request, current_user)
create_mention_todos(merge_request.project, merge_request, current_user)
end
# When close a merge request we should:
#
# * mark all pending tasks related to the target for the current user as done
# * mark all pending todos related to the target for the current user as done
#
def close_merge_request(merge_request, current_user)
mark_pending_tasks_as_done(merge_request, current_user)
mark_pending_todos_as_done(merge_request, current_user)
end
# When we reassign a merge request we should:
#
# * creates a pending task for new assignee if merge request is assigned
# * creates a pending todo for new assignee if merge request is assigned
#
def reassigned_merge_request(merge_request, current_user)
create_assignment_task(merge_request, current_user)
create_assignment_todo(merge_request, current_user)
end
# When merge a merge request we should:
#
# * mark all pending tasks related to the target for the current user as done
# * mark all pending todos related to the target for the current user as done
#
def merge_merge_request(merge_request, current_user)
mark_pending_tasks_as_done(merge_request, current_user)
mark_pending_todos_as_done(merge_request, current_user)
end
# When create a note we should:
#
# * mark all pending tasks related to the noteable for the note author as done
# * create a task for each mentioned user on note
# * mark all pending todos related to the noteable for the note author as done
# * create a todo for each mentioned user on note
#
def new_note(note, current_user)
handle_note(note, current_user)
......@@ -91,28 +91,28 @@ class TaskService
# When update a note we should:
#
# * mark all pending tasks related to the noteable for the current user as done
# * create a task for each new user mentioned on note
# * mark all pending todos related to the noteable for the current user as done
# * create a todo for each new user mentioned on note
#
def update_note(note, current_user)
handle_note(note, current_user)
end
# When marking pending tasks as done we should:
# When marking pending todos as done we should:
#
# * mark all pending tasks related to the target for the current user as done
# * mark all pending todos related to the target for the current user as done
#
def mark_pending_tasks_as_done(target, user)
pending_tasks(user, target.project, target).update_all(state: :done)
def mark_pending_todos_as_done(target, user)
pending_todos(user, target.project, target).update_all(state: :done)
end
private
def create_tasks(project, target, author, users, action, note = nil)
def create_todos(project, target, author, users, action, note = nil)
Array(users).each do |user|
next if pending_tasks(user, project, target).exists?
next if pending_todos(user, project, target).exists?
Task.create(
Todo.create(
project: project,
user_id: user.id,
author_id: author.id,
......@@ -125,8 +125,8 @@ class TaskService
end
def new_issuable(issuable, author)
create_assignment_task(issuable, author)
create_mention_tasks(issuable.project, issuable, author)
create_assignment_todo(issuable, author)
create_mention_todos(issuable.project, issuable, author)
end
def handle_note(note, author)
......@@ -136,19 +136,19 @@ class TaskService
project = note.project
target = note.noteable
mark_pending_tasks_as_done(target, author)
create_mention_tasks(project, target, author, note)
mark_pending_todos_as_done(target, author)
create_mention_todos(project, target, author, note)
end
def create_assignment_task(issuable, author)
def create_assignment_todo(issuable, author)
if issuable.assignee && issuable.assignee != author
create_tasks(issuable.project, issuable, author, issuable.assignee, Task::ASSIGNED)
create_todos(issuable.project, issuable, author, issuable.assignee, Todo::ASSIGNED)
end
end
def create_mention_tasks(project, issuable, author, note = nil)
def create_mention_todos(project, issuable, author, note = nil)
mentioned_users = filter_mentioned_users(project, note || issuable, author)
create_tasks(project, issuable, author, mentioned_users, Task::MENTIONED, note)
create_todos(project, issuable, author, mentioned_users, Todo::MENTIONED, note)
end
def filter_mentioned_users(project, target, author)
......@@ -160,8 +160,8 @@ class TaskService
mentioned_users.uniq
end
def pending_tasks(user, project, target)
user.tasks.pending.where(
def pending_todos(user, project, target)
user.todos.pending.where(
project_id: project.id,
target_id: target.id,
target_type: target.class.name
......
%li{class: "task task-#{task.done? ? 'done' : 'pending'}", id: dom_id(task) }
.task-item{class: 'task-block'}
= image_tag avatar_icon(task.author_email, 40), class: 'avatar s40', alt:''
.task-title
%span.author_name
= link_to_author task
%span.task_label
= task_action_name(task)
= task_target_link_html(task)
&middot; #{time_ago_with_tooltip(task.created_at)}
- if task.pending?
.task-actions.pull-right
= link_to 'Done', [:dashboard, task], method: :delete, class: 'btn'
.task-body
.task-note
.md
= event_note(task.body, project: task.project)
%li{class: "todo todo-#{todo.done? ? 'done' : 'pending'}", id: dom_id(todo) }
.todo-item{class: 'todo-block'}
= image_tag avatar_icon(todo.author_email, 40), class: 'avatar s40', alt:''
.todo-title
%span.author_name
= link_to_author todo
%span.todo_label
= todo_action_name(todo)
= todo_target_link_html(todo)
&middot; #{time_ago_with_tooltip(todo.created_at)}
- if todo.pending?
.todo-actions.pull-right
= link_to 'Done', [:dashboard, todo], method: :delete, class: 'btn'
.todo-body
.todo-note
.md
= event_note(todo.body, project: todo.project)
- page_title "Tasks"
- header_title "Tasks", dashboard_tasks_path
- page_title "Todos"
- header_title "Todos", dashboard_todos_path
.top-area
%ul.nav-links
%li{class: ('active' if params[:state].blank? || params[:state] == 'pending')}
= link_to page_filter_path(state: 'pending') do
%span
Tasks
Todos
%span{class: 'badge'}
= tasks_pending_count
= todos_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
= todos_done_count
.tasks-filters
.todos-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,
= select_tag('project_id', todo_projects_options,