diff options
author | Andreas Brandl <abrandl@gitlab.com> | 2018-02-27 21:42:06 +0100 |
---|---|---|
committer | Andreas Brandl <abrandl@gitlab.com> | 2018-02-27 21:42:06 +0100 |
commit | 972aaa258dedb57a71bcae87c450ee7c0d293459 (patch) | |
tree | 33153f5bd1f4bdfa9efefdf07b68898ab3c858e5 | |
parent | 810986433eab68e98db56fb63902a8c0547752cb (diff) | |
download | gitlab-ce-30641-snooze-todos.tar.gz |
-rw-r--r-- | app/assets/javascripts/pages/dashboard/todos/index/todos.js | 21 | ||||
-rw-r--r-- | app/controllers/dashboard/todos_controller.rb | 15 | ||||
-rw-r--r-- | app/finders/todos_finder.rb | 2 | ||||
-rw-r--r-- | app/helpers/todos_helper.rb | 4 | ||||
-rw-r--r-- | app/models/todo.rb | 18 | ||||
-rw-r--r-- | app/models/user.rb | 7 | ||||
-rw-r--r-- | app/services/todo_service.rb | 26 | ||||
-rw-r--r-- | app/views/dashboard/todos/_todo.html.haml | 20 | ||||
-rw-r--r-- | app/views/dashboard/todos/index.html.haml | 6 | ||||
-rw-r--r-- | config/routes/dashboard.rb | 2 | ||||
-rw-r--r-- | db/migrate/20180227182036_add_snoozed_until_to_todos.rb | 9 | ||||
-rw-r--r-- | db/schema.rb | 10 |
12 files changed, 136 insertions, 4 deletions
diff --git a/app/assets/javascripts/pages/dashboard/todos/index/todos.js b/app/assets/javascripts/pages/dashboard/todos/index/todos.js index b3f6a72fdcb..96527705685 100644 --- a/app/assets/javascripts/pages/dashboard/todos/index/todos.js +++ b/app/assets/javascripts/pages/dashboard/todos/index/todos.js @@ -22,7 +22,7 @@ export default class Todos { } unbindEvents() { - $('.js-done-todo, .js-undo-todo, .js-add-todo').off('click', this.updateRowStateClickedWrapper); + $('.js-done-todo, .js-undo-todo, .js-add-todo, .js-snooze-todo, .js-unsnooze-todo').off('click', this.updateRowStateClickedWrapper); $('.js-todos-mark-all', '.js-todos-undo-all').off('click', this.updateallStateClickedWrapper); $('.todo').off('click', this.goToTodoUrl); } @@ -31,7 +31,7 @@ export default class Todos { this.updateRowStateClickedWrapper = this.updateRowStateClicked.bind(this); this.updateAllStateClickedWrapper = this.updateAllStateClicked.bind(this); - $('.js-done-todo, .js-undo-todo, .js-add-todo').on('click', this.updateRowStateClickedWrapper); + $('.js-done-todo, .js-undo-todo, .js-add-todo, .js-snooze-todo, .js-unsnooze-todo').on('click', this.updateRowStateClickedWrapper); $('.js-todos-mark-all, .js-todos-undo-all').on('click', this.updateAllStateClickedWrapper); $('.todo').on('click', this.goToTodoUrl); } @@ -74,6 +74,8 @@ export default class Todos { const row = target.closest('li'); const restoreBtn = row.querySelector('.js-undo-todo'); const doneBtn = row.querySelector('.js-done-todo'); + const snoozeBtn = row.querySelector('.js-snooze-todo'); + const unsnoozeBtn = row.querySelector('.js-unsnooze-todo'); target.classList.add('hidden'); target.removeAttribute('disabled'); @@ -82,9 +84,23 @@ export default class Todos { if (target === doneBtn) { row.classList.add('done-reversible'); restoreBtn.classList.remove('hidden'); + snoozeBtn.classList.add('hidden'); + unsnoozeBtn.classList.add('hidden'); } else if (target === restoreBtn) { row.classList.remove('done-reversible'); doneBtn.classList.remove('hidden'); + snoozeBtn.classList.remove('hidden'); + unsnoozeBtn.classList.add('hidden'); + } else if (target === snoozeBtn) { + row.classList.add('done-reversible'); + doneBtn.classList.add('hidden'); + snoozeBtn.classList.add('hidden'); + unsnoozeBtn.classList.remove('hidden'); + } else if (target === unsnoozeBtn) { + row.classList.remove('done-reversible'); + doneBtn.classList.remove('hidden'); + snoozeBtn.classList.remove('hidden'); + unsnoozeBtn.classList.add('hidden'); } else { row.parentNode.removeChild(row); } @@ -125,6 +141,7 @@ export default class Todos { updateBadges(data) { $(document).trigger('todo:toggle', data.count); document.querySelector('.todos-pending .badge').innerHTML = data.count; + document.querySelector('.todos-snoozed .badge').innerHTML = data.snoozed_count; document.querySelector('.todos-done .badge').innerHTML = data.done_count; } diff --git a/app/controllers/dashboard/todos_controller.rb b/app/controllers/dashboard/todos_controller.rb index e89eaf7edda..36796f3613a 100644 --- a/app/controllers/dashboard/todos_controller.rb +++ b/app/controllers/dashboard/todos_controller.rb @@ -41,6 +41,18 @@ class Dashboard::TodosController < Dashboard::ApplicationController render json: todos_counts end + def snooze + TodoService.new.mark_todos_as_snoozed_by_ids(params[:id], current_user) + + render json: todos_counts + end + + def unsnooze + TodoService.new.mark_todos_as_unsnoozed_by_ids(params[:id], current_user) + + render json: todos_counts + end + def bulk_restore TodoService.new.mark_todos_as_pending_by_ids(params[:ids], current_user) @@ -65,7 +77,8 @@ class Dashboard::TodosController < Dashboard::ApplicationController def todos_counts { count: number_with_delimiter(current_user.todos_pending_count), - done_count: number_with_delimiter(current_user.todos_done_count) + done_count: number_with_delimiter(current_user.todos_done_count), + snoozed_count: number_with_delimiter(current_user.todos_snoozed_count) } end diff --git a/app/finders/todos_finder.rb b/app/finders/todos_finder.rb index edb17843002..44c7ea971dc 100644 --- a/app/finders/todos_finder.rb +++ b/app/finders/todos_finder.rb @@ -165,6 +165,8 @@ class TodosFinder case params[:state].to_s when 'done' items.done + when 'snoozed' + items.snoozed else items.pending end diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index ddb48371c79..c671a263b76 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -11,6 +11,10 @@ module TodosHelper @todos_done_count ||= current_user.todos_done_count end + def todos_snoozed_count + @todos_snoozed_count ||= current_user.todos_snoozed_count + end + def todo_action_name(todo) case todo.action when Todo::ASSIGNED then todo.self_added? ? 'assigned' : 'assigned you' diff --git a/app/models/todo.rb b/app/models/todo.rb index bb5965e20eb..f9f5ba5d452 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -36,14 +36,32 @@ class Todo < ActiveRecord::Base scope :pending, -> { with_state(:pending) } scope :done, -> { with_state(:done) } + scope :snoozed, -> { with_state(:snoozed) } state_machine :state, initial: :pending do event :done do transition [:pending] => :done end + event :snooze do + transition [:pending] => :snoozed + end + + event :unsnooze do + transition [:snoozed] => :pending + end + + before_transition [:pending] => :snoozed do |todo| + todo.snoozed_until = Time.now + 1.day + end + + before_transition [:snoozed] => :pending do |todo| + todo.snoozed_until = nil + end + state :pending state :done + state :snoozed end after_save :keep_around_commit diff --git a/app/models/user.rb b/app/models/user.rb index 982080763d2..492b3d276a0 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1056,9 +1056,16 @@ class User < ActiveRecord::Base end end + def todos_snoozed_count(force: false) + Rails.cache.fetch(['users', id, 'todos_snoozed_count'], force: force, expires_in: 20.minutes) do + TodosFinder.new(self, state: :snoozed).execute.count + end + end + def update_todos_count_cache todos_done_count(force: true) todos_pending_count(force: true) + todos_snoozed_count(force: true) end # This is copied from Devise::Models::Lockable#valid_for_authentication?, as our auth diff --git a/app/services/todo_service.rb b/app/services/todo_service.rb index c2ca404b179..a3811d0b015 100644 --- a/app/services/todo_service.rb +++ b/app/services/todo_service.rb @@ -188,6 +188,32 @@ class TodoService mark_todos_as_pending(todos, current_user) end + # When user marks some todos as snoozed + def mark_todos_as_snoozed(todos, current_user) + todos.each do |todo| + todo.snooze + end + current_user.update_todos_count_cache + end + + def mark_todos_as_snoozed_by_ids(ids, current_user) + todos = todos_by_ids(ids, current_user) + mark_todos_as_snoozed(todos, current_user) + end + + # When user marks some todos as unsnoozed + def mark_todos_as_unsnoozed(todos, current_user) + todos.each do |todo| + todo.unsnooze + end + current_user.update_todos_count_cache + end + + def mark_todos_as_unsnoozed_by_ids(ids, current_user) + todos = todos_by_ids(ids, current_user) + mark_todos_as_unsnoozed(todos, current_user) + 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) diff --git a/app/views/dashboard/todos/_todo.html.haml b/app/views/dashboard/todos/_todo.html.haml index efe1fb99efc..f71079b5b9c 100644 --- a/app/views/dashboard/todos/_todo.html.haml +++ b/app/views/dashboard/todos/_todo.html.haml @@ -46,6 +46,26 @@ = link_to restore_dashboard_todo_path(todo), method: :patch, class: 'btn btn-loading js-undo-todo hidden', data: { href: restore_dashboard_todo_path(todo) } do Undo = icon('spinner spin') + = link_to snooze_dashboard_todo_path(todo), method: :patch, class: 'btn btn-loading js-snooze-todo', data: { href: snooze_dashboard_todo_path(todo) } do + Snooze + = icon('spinner spin') + = link_to unsnooze_dashboard_todo_path(todo), method: :patch, class: 'btn btn-loading js-unsnooze-todo hidden', data: { href: unsnooze_dashboard_todo_path(todo) } do + Unsnooze + = icon('spinner spin') + - elsif todo.snoozed? + .todo-actions + = link_to dashboard_todo_path(todo), method: :delete, class: 'btn btn-loading js-done-todo', data: { href: dashboard_todo_path(todo) } do + Done + = icon('spinner spin') + = link_to restore_dashboard_todo_path(todo), method: :patch, class: 'btn btn-loading js-undo-todo hidden', data: { href: restore_dashboard_todo_path(todo) } do + Undo + = icon('spinner spin') + = link_to snooze_dashboard_todo_path(todo), method: :patch, class: 'btn btn-loading js-snooze-todo hidden', data: { href: snooze_dashboard_todo_path(todo) } do + Snooze + = icon('spinner spin') + = link_to unsnooze_dashboard_todo_path(todo), method: :patch, class: 'btn btn-loading js-unsnooze-todo', data: { href: unsnooze_dashboard_todo_path(todo) } do + Unsnooze + = icon('spinner spin') - else .todo-actions = link_to restore_dashboard_todo_path(todo), method: :patch, class: 'btn btn-loading js-add-todo', data: { href: restore_dashboard_todo_path(todo) } do diff --git a/app/views/dashboard/todos/index.html.haml b/app/views/dashboard/todos/index.html.haml index 664966989db..4830ae90a91 100644 --- a/app/views/dashboard/todos/index.html.haml +++ b/app/views/dashboard/todos/index.html.haml @@ -11,6 +11,12 @@ Todos %span.badge = number_with_delimiter(todos_pending_count) + %li.todos-snoozed{ class: active_when(params[:state].blank? || params[:state] == 'snoozed') }> + = link_to todos_filter_path(state: 'snoozed') do + %span + Snoozed + %span.badge + = number_with_delimiter(todos_snoozed_count) %li.todos-done{ class: active_when(params[:state] == 'done') }> = link_to todos_filter_path(state: 'done') do %span diff --git a/config/routes/dashboard.rb b/config/routes/dashboard.rb index d2437285cdf..2765e6ea326 100644 --- a/config/routes/dashboard.rb +++ b/config/routes/dashboard.rb @@ -23,6 +23,8 @@ resource :dashboard, controller: 'dashboard', only: [] do end member do patch :restore + patch :snooze + patch :unsnooze end end diff --git a/db/migrate/20180227182036_add_snoozed_until_to_todos.rb b/db/migrate/20180227182036_add_snoozed_until_to_todos.rb new file mode 100644 index 00000000000..6242d5a6f4e --- /dev/null +++ b/db/migrate/20180227182036_add_snoozed_until_to_todos.rb @@ -0,0 +1,9 @@ +class AddSnoozedUntilToTodos < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + def change + add_column :todos, :snoozed_until, :datetime_with_timezone + end +end diff --git a/db/schema.rb b/db/schema.rb index 5bb461169f1..7acd00eaf5b 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20180216121030) do +ActiveRecord::Schema.define(version: 20180227182036) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -1735,6 +1735,7 @@ ActiveRecord::Schema.define(version: 20180216121030) do t.datetime "updated_at" t.integer "note_id" t.string "commit_id" + t.datetime_with_timezone "snoozed_until" end add_index "todos", ["author_id"], name: "index_todos_on_author_id", using: :btree @@ -1800,6 +1801,13 @@ ActiveRecord::Schema.define(version: 20180216121030) do add_index "user_callouts", ["user_id", "feature_name"], name: "index_user_callouts_on_user_id_and_feature_name", unique: true, using: :btree add_index "user_callouts", ["user_id"], name: "index_user_callouts_on_user_id", using: :btree + create_table "user_contributed_projects", id: false, force: :cascade do |t| + t.integer "user_id", null: false + t.integer "project_id", null: false + end + + add_index "user_contributed_projects", ["user_id", "project_id"], name: "index_user_contributed_projects_on_user_id_and_project_id", unique: true, using: :btree + create_table "user_custom_attributes", force: :cascade do |t| t.datetime_with_timezone "created_at", null: false t.datetime_with_timezone "updated_at", null: false |