Commit f67b06ad authored by Phil Hughes's avatar Phil Hughes

Manually create todo for issuable

Added a button into the sidebar for issues & merge requests to allow users to manually create todo items

Closes #15045
parent f34af6b8
......@@ -43,6 +43,45 @@ class @Sidebar
$('.right-sidebar')
.hasClass('right-sidebar-collapsed'), { path: '/' })
$(document)
.off 'click', '.js-issuable-todo'
.on 'click', '.js-issuable-todo', @toggleTodo
toggleTodo: (e) ->
$this = $(@)
$btnText = $this.find('span')
data = {
todo_id: $this.attr('data-id')
}
$.ajax(
url: $this.data('url')
type: 'POST'
dataType: 'json'
data: data
beforeSend: ->
$this.disable()
$('.js-issuable-todo-loading').removeClass 'hidden'
).done (data) ->
$todoPendingCount = $('.todos-pending-count')
$todoPendingCount.text data.count
$this.enable()
$('.js-issuable-todo-loading').addClass 'hidden'
if data.count is 0
$this.removeAttr 'data-id'
$btnText.text $this.data('todo-text')
$todoPendingCount
.addClass 'hidden'
else
$btnText.text $this.data('mark-text')
$todoPendingCount
.removeClass 'hidden'
if data.todo?
$this.attr 'data-id', data.todo.id
sidebarDropdownLoading: (e) ->
$sidebarCollapsedIcon = $(@).closest('.block').find('.sidebar-collapsed-icon')
......@@ -117,5 +156,3 @@ class @Sidebar
getBlock: (name) ->
@sidebar.find(".block.#{name}")
......@@ -34,6 +34,10 @@
color: inherit;
}
.issuable-header-text {
margin-top: 7px;
}
.block {
@include clearfix;
padding: $gl-padding 0;
......@@ -60,10 +64,6 @@
margin-top: 0;
}
.issuable-count {
margin-top: 7px;
}
.gutter-toggle {
margin-left: 20px;
padding-left: 10px;
......@@ -250,7 +250,7 @@
}
}
.issuable-pager {
.issuable-header-btn {
background: $gray-normal;
border: 1px solid $border-gray-normal;
&:hover {
......@@ -263,7 +263,7 @@
}
}
a:not(.issuable-pager) {
a:not(.issuable-header-btn) {
&:hover {
color: $md-link-color;
text-decoration: none;
......
......@@ -164,6 +164,20 @@ class Projects::IssuesController < Projects::ApplicationController
end
end
def todo
json_data = Hash.new
if params[:todo_id].nil?
TodoService.new.mark_todo(issue, current_user)
json_data[:todo] = current_user.todos.find_by(state: :pending, action: Todo::MARKED, target_id: issue.id)
else
current_user.todos.find_by_id(params[:todo_id]).update(state: :done)
end
render json: json_data.merge({ count: current_user.todos.pending.count })
end
protected
def issue
......
......@@ -260,6 +260,20 @@ class Projects::MergeRequestsController < Projects::ApplicationController
render json: response
end
def todo
json_data = Hash.new
if params[:todo_id].nil?
TodoService.new.mark_todo(merge_request, current_user)
json_data[:todo] = current_user.todos.find_by(state: :pending, action: Todo::MARKED, target_id: merge_request.id)
else
current_user.todos.find_by_id(params[:todo_id]).update(state: :done)
end
render json: json_data.merge({ count: current_user.todos.pending.count })
end
protected
def selected_target_project
......
......@@ -36,7 +36,7 @@ class TodosFinder
private
def action_id?
action_id.present? && [Todo::ASSIGNED, Todo::MENTIONED, Todo::BUILD_FAILED].include?(action_id.to_i)
action_id.present? && [Todo::ASSIGNED, Todo::MENTIONED, Todo::BUILD_FAILED, Todo::MARKED].include?(action_id.to_i)
end
def action_id
......
......@@ -67,6 +67,20 @@ module IssuablesHelper
end
end
def issuable_todo_path(issuable)
project = issuable.project
if issuable.kind_of?(MergeRequest)
todo_namespace_project_merge_request_path(project.namespace, project, issuable.iid, :json)
else
todo_namespace_project_issue_path(project.namespace, project, issuable.iid, :json)
end
end
def has_todo(issuable)
current_user.todos.find_by(target_id: issuable.id, state: :pending)
end
private
def sidebar_gutter_collapsed?
......
......@@ -2,6 +2,7 @@ class Todo < ActiveRecord::Base
ASSIGNED = 1
MENTIONED = 2
BUILD_FAILED = 3
MARKED = 4
belongs_to :author, class_name: "User"
belongs_to :note
......
......@@ -139,6 +139,12 @@ class TodoService
pending_todos(user, attributes).update_all(state: :done)
end
# When user marks an issue as todo
def mark_todo(issuable, current_user)
attributes = attributes_for_todo(issuable.project, issuable, current_user, Todo::MARKED)
create_todos(current_user, attributes)
end
private
def create_todos(users, attributes)
......
......@@ -27,9 +27,8 @@
%li
= link_to dashboard_todos_path, title: 'Todos', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= icon('bell fw')
- unless todos_pending_count == 0
%span.badge.todos-pending-count
= todos_pending_count
%span.badge.todos-pending-count{ class: ("hidden" if todos_pending_count == 0)}
= todos_pending_count
- if current_user.can_create_project?
%li
= link_to new_project_path, title: 'New project', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
......
- todo = has_todo(issuable)
%aside.right-sidebar{ class: sidebar_gutter_collapsed_class }
.issuable-sidebar
- can_edit_issuable = can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
.block.issuable-sidebar-header
%a.gutter-toggle.pull-right.js-sidebar-toggle{href: '#'}
%span.issuable-header-text.hide-collapsed.pull-left
Todo
%button.gutter-toggle.pull-right.js-sidebar-toggle{ type: "button", aria: { label: "Toggle sidebar" } }
= sidebar_gutter_toggle_icon
%button.btn.btn-default.issuable-header-btn.pull-right.js-issuable-todo{ type: "button", data: { todo_text: "Add Todo", mark_text: "Mark Done", id: (todo.id unless todo.nil?), url: issuable_todo_path(issuable) } }
- if todo.nil?
%span
Add Todo
- else
%span
Mark Done
= icon('spin spinner', class: 'hidden js-issuable-todo-loading')
= form_for [@project.namespace.becomes(Namespace), @project, issuable], remote: true, format: :json, html: {class: 'issuable-context-form inline-update js-issuable-update'} do |f|
.block.assignee
......
......@@ -679,6 +679,7 @@ Rails.application.routes.draw do
post :toggle_subscription
post :toggle_award_emoji
post :remove_wip
post :todo
end
collection do
......@@ -759,6 +760,7 @@ Rails.application.routes.draw do
get :referenced_merge_requests
get :related_branches
get :can_create_branch
post :todo
end
collection do
post :bulk_update
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment