From f67b06ada016915211e84a7d12a063aa25e422f3 Mon Sep 17 00:00:00 2001 From: Phil Hughes <me@iamphill.com> Date: Tue, 7 Jun 2016 09:44:01 +0100 Subject: [PATCH] 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 --- .../javascripts/right_sidebar.js.coffee | 41 ++++++++++++++++++- app/assets/stylesheets/pages/issuable.scss | 12 +++--- app/controllers/projects/issues_controller.rb | 14 +++++++ .../projects/merge_requests_controller.rb | 14 +++++++ app/finders/todos_finder.rb | 2 +- app/helpers/issuables_helper.rb | 14 +++++++ app/models/todo.rb | 1 + app/services/todo_service.rb | 6 +++ app/views/layouts/header/_default.html.haml | 5 +-- app/views/shared/issuable/_sidebar.html.haml | 13 +++++- config/routes.rb | 2 + 11 files changed, 111 insertions(+), 13 deletions(-) diff --git a/app/assets/javascripts/right_sidebar.js.coffee b/app/assets/javascripts/right_sidebar.js.coffee index c9cb0f4bb32..3ee943fe78c 100644 --- a/app/assets/javascripts/right_sidebar.js.coffee +++ b/app/assets/javascripts/right_sidebar.js.coffee @@ -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}") - - diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index ea453ce356a..acbb7e7f713 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -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; diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index 4e2d3bebb2e..5678d584d4a 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -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 diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 67e7187c10d..f0eba453caa 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -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 diff --git a/app/finders/todos_finder.rb b/app/finders/todos_finder.rb index 1d88116d7d2..aa47c6c157e 100644 --- a/app/finders/todos_finder.rb +++ b/app/finders/todos_finder.rb @@ -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 diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb index 40d8ce8a1d3..88ef1a6468c 100644 --- a/app/helpers/issuables_helper.rb +++ b/app/helpers/issuables_helper.rb @@ -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? diff --git a/app/models/todo.rb b/app/models/todo.rb index 3a091373329..2792fa9b9a8 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -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 diff --git a/app/services/todo_service.rb b/app/services/todo_service.rb index 8e03ff8ddde..5a192e54f25 100644 --- a/app/services/todo_service.rb +++ b/app/services/todo_service.rb @@ -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) diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml index ad30a367fc5..ebc9f01675a 100644 --- a/app/views/layouts/header/_default.html.haml +++ b/app/views/layouts/header/_default.html.haml @@ -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 diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml index fb906de829a..25d830b6e49 100644 --- a/app/views/shared/issuable/_sidebar.html.haml +++ b/app/views/shared/issuable/_sidebar.html.haml @@ -1,9 +1,20 @@ +- 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 diff --git a/config/routes.rb b/config/routes.rb index 95fbe7dd9df..d018fa742cc 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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 -- 2.30.9