summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Brandl <abrandl@gitlab.com>2018-02-27 21:42:06 +0100
committerAndreas Brandl <abrandl@gitlab.com>2018-02-27 21:42:06 +0100
commit972aaa258dedb57a71bcae87c450ee7c0d293459 (patch)
tree33153f5bd1f4bdfa9efefdf07b68898ab3c858e5
parent810986433eab68e98db56fb63902a8c0547752cb (diff)
downloadgitlab-ce-30641-snooze-todos.tar.gz
-rw-r--r--app/assets/javascripts/pages/dashboard/todos/index/todos.js21
-rw-r--r--app/controllers/dashboard/todos_controller.rb15
-rw-r--r--app/finders/todos_finder.rb2
-rw-r--r--app/helpers/todos_helper.rb4
-rw-r--r--app/models/todo.rb18
-rw-r--r--app/models/user.rb7
-rw-r--r--app/services/todo_service.rb26
-rw-r--r--app/views/dashboard/todos/_todo.html.haml20
-rw-r--r--app/views/dashboard/todos/index.html.haml6
-rw-r--r--config/routes/dashboard.rb2
-rw-r--r--db/migrate/20180227182036_add_snoozed_until_to_todos.rb9
-rw-r--r--db/schema.rb10
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