thredded-workgroup 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +12 -4
  3. data/.rubocop_todo.yml +170 -0
  4. data/.travis.yml +3 -3
  5. data/CHANGELOG.md +9 -0
  6. data/Gemfile +1 -0
  7. data/Guardfile +16 -39
  8. data/README.md +27 -10
  9. data/Rakefile +1 -0
  10. data/app/assets/config/thredded_workgroup_manifest.js +3 -0
  11. data/app/assets/images/thredded/workgroup/envelope-o.svg +2 -0
  12. data/app/assets/images/thredded/workgroup/envelope-open-o.svg +2 -0
  13. data/app/assets/javascripts/thredded-workgroup.js +1 -13
  14. data/app/assets/javascripts/thredded/workgroup/components/followers.es6 +24 -0
  15. data/app/assets/javascripts/thredded/workgroup/components/overflow.es6 +60 -0
  16. data/app/assets/javascripts/thredded/workgroup/components/topics.es6 +151 -0
  17. data/app/assets/javascripts/thredded/workgroup/core/thredded_workgroup.js +1 -0
  18. data/app/assets/javascripts/thredded/workgroup/core/touch.es6 +16 -0
  19. data/app/assets/javascripts/thredded/workgroup/index.js +3 -0
  20. data/app/assets/stylesheets/thredded-workgroup.scss +2 -0
  21. data/app/assets/stylesheets/thredded/workgroup/_followers.scss +51 -0
  22. data/app/assets/stylesheets/thredded/workgroup/_navs.scss +29 -7
  23. data/app/assets/stylesheets/thredded/workgroup/_overflow.scss +71 -0
  24. data/app/assets/stylesheets/thredded/workgroup/_topics.scss +186 -16
  25. data/app/controllers/concerns/thredded/workgroup/all_unread_followed_topics.rb +31 -0
  26. data/app/controllers/thredded/application_controller.rb +23 -0
  27. data/app/controllers/thredded/posts_controller.rb +1 -0
  28. data/app/controllers/thredded/workgroup/application_controller.rb +1 -0
  29. data/app/controllers/thredded/workgroup/navs_controller.rb +1 -0
  30. data/app/controllers/thredded/workgroup/read_states_controller.rb +14 -0
  31. data/app/controllers/thredded/workgroup/topics_controller.rb +18 -0
  32. data/app/helpers/thredded/application_helper.rb +1 -0
  33. data/app/helpers/thredded/workgroup/application_helper.rb +1 -0
  34. data/app/jobs/thredded/workgroup/mark_all_topics_read_job.rb +13 -0
  35. data/app/view_hooks/thredded/all_view_hooks.rb +9 -0
  36. data/app/view_hooks/thredded/workgroup/view_hooks.rb +28 -0
  37. data/app/view_models/thredded/topic_view.rb +17 -0
  38. data/app/view_models/thredded/topics_page_view.rb +1 -0
  39. data/app/views/thredded/shared/nav/_unread_topics.html.erb +1 -0
  40. data/app/views/thredded/topics/_followers.html.erb +23 -0
  41. data/app/views/thredded/topics/_topic.html.erb +25 -28
  42. data/app/views/thredded/workgroup/navs/_personal_nav.html.erb +7 -1
  43. data/app/views/thredded/workgroup/navs/all_topics.html.erb +1 -1
  44. data/app/views/thredded/workgroup/navs/awaiting.html.erb +1 -1
  45. data/app/views/thredded/workgroup/navs/following.html.erb +1 -1
  46. data/app/views/thredded/workgroup/navs/unread.html.erb +1 -1
  47. data/app/views/thredded/workgroup/topics/_controls.html.erb +21 -0
  48. data/app/views/thredded/workgroup/topics/_last_post.html.erb +11 -0
  49. data/app/views/thredded/workgroup/topics/_last_post_with_controls.html.erb +12 -0
  50. data/app/views/thredded/workgroup/topics/_topics_with_last_post.html.erb +16 -0
  51. data/bin/rails.rb +1 -0
  52. data/bin/rspec +1 -0
  53. data/bin/update_from_thredded +1 -0
  54. data/config/locales/en.yml +11 -0
  55. data/config/routes.rb +9 -0
  56. data/docs/followers-above-post.png +0 -0
  57. data/docs/navbar.png +0 -0
  58. data/lib/thredded/workgroup.rb +1 -0
  59. data/lib/thredded/workgroup/engine.rb +11 -2
  60. data/lib/thredded/workgroup/thredded_route_delegator.rb +1 -0
  61. data/lib/thredded/workgroup/version.rb +2 -1
  62. data/shared.gemfile +4 -0
  63. data/thredded-workgroup.gemspec +6 -10
  64. metadata +62 -60
  65. data/app/assets/javascripts/thredded/workgroup/follow.js +0 -36
  66. data/app/assets/javascripts/thredded/workgroup/topics.js +0 -18
  67. data/app/views/thredded/topics/_topics_with_last_post.html.erb +0 -14
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thredded
4
+ module Workgroup
5
+ module AllUnreadFollowedTopics
6
+ extend ActiveSupport::Concern
7
+ included do
8
+ include Pundit
9
+ helper_method :all_unread_followed_topics_count
10
+ end
11
+
12
+ # @return [ActiveRecord::Relation]
13
+ def all_topics_scope
14
+ @all_topics_scope ||=
15
+ policy_scope(Thredded::Topic.all).joins(:messageboard).merge(policy_scope(Thredded::Messageboard.all))
16
+ end
17
+
18
+ # @return Integer
19
+ def all_unread_followed_topics_count
20
+ @all_unread_followed_topics_count ||=
21
+ if thredded_signed_in?
22
+ all_topics_scope.unread_followed_by(thredded_current_user).count
23
+ else
24
+ 0
25
+ end
26
+ end
27
+
28
+ # need to define `thredded_current_user` and possibly `pundit_user`
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency File.expand_path("../../app/controllers/thredded/application_controller",
4
+ Thredded::Engine.called_from)
5
+
6
+ module Thredded
7
+ module ApplicationControllerRetaining
8
+ def topics_scope
9
+ return super if messageboard_or_nil
10
+ all_topics_scope
11
+ end
12
+
13
+ def unread_followed_topics_count
14
+ return super if messageboard_or_nil
15
+ all_unread_followed_topics_count
16
+ end
17
+ end
18
+ class ApplicationController
19
+ include Thredded::Workgroup::AllUnreadFollowedTopics
20
+
21
+ prepend ::Thredded::ApplicationControllerRetaining
22
+ end
23
+ end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_dependency File.expand_path("../../app/controllers/thredded/posts_controller", Thredded::Engine.called_from)
3
4
 
4
5
  module Thredded
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Thredded
3
4
  module Workgroup
4
5
  class ApplicationController < Thredded::ApplicationController
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Thredded
3
4
  module Workgroup
4
5
  class NavsController < Thredded::Workgroup::ApplicationController
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thredded
4
+ module Workgroup
5
+ class ReadStatesController < ::Thredded::Workgroup::ApplicationController
6
+ before_action :thredded_require_login!
7
+
8
+ def mark_all_topics_read
9
+ ::Thredded::Workgroup::MarkAllTopicsReadJob.perform_later(thredded_current_user) if thredded_signed_in?
10
+ redirect_to request.referer, flash: { notice: "Marking all topics as read (will take a few seconds)" }
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ # frozen_string_literal: true # frozen_string_literal: true
4
+
5
+ module Thredded
6
+ module Workgroup
7
+ class TopicsController < Thredded::Workgroup::ApplicationController
8
+ before_action :thredded_require_login!
9
+
10
+ def kick
11
+ if (user_topic_follow = UserTopicFollow.where(topic_id: params[:id], user_id: params[:user_id]).first)
12
+ user_topic_follow.destroy
13
+ end
14
+ render plain: "Ok"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_dependency File.expand_path("../../app/helpers/thredded/application_helper", Thredded::Engine.called_from)
3
4
  module Thredded
4
5
  module ApplicationHelper
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Thredded
3
4
  module Workgroup
4
5
  module ApplicationHelper
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thredded
4
+ module Workgroup
5
+ class MarkAllTopicsReadJob < ::ActiveJob::Base
6
+ def perform(user)
7
+ ::Thredded::Topic.unread(user).each do |topic|
8
+ ::Thredded::UserTopicReadState.touch!(user.id, topic.last_post)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency File.expand_path("../../app/view_hooks/thredded/all_view_hooks", Thredded::Engine.called_from)
4
+
5
+ module Thredded
6
+ class AllViewHooks
7
+ prepend ::Thredded::Workgroup::ViewHooks
8
+ end
9
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thredded
4
+ module Workgroup
5
+ module ViewHooks
6
+ attr_reader :topic_with_last_post
7
+
8
+ def initialize
9
+ super
10
+ @topic_with_last_post = TopicWithLastPost.new
11
+ end
12
+
13
+ # View hooks for a Topic when displaying last post.
14
+ class TopicWithLastPost
15
+ # @return [Thredded::AllViewHooks::ViewHook]
16
+ attr_reader :last_post_with_controls
17
+
18
+ # @return [Thredded::AllViewHooks::ViewHook]
19
+ attr_reader :last_post
20
+
21
+ def initialize
22
+ @last_post_with_controls = Thredded::AllViewHooks::ViewHook.new
23
+ @last_post = Thredded::AllViewHooks::ViewHook.new
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_dependency File.expand_path("../../app/view_models/thredded/topic_view", Thredded::Engine.called_from)
3
4
  module Thredded
4
5
  class TopicView < Thredded::BaseTopicView
@@ -11,5 +12,21 @@ module Thredded
11
12
  page = @read_state.first_unread_post_page || @read_state.last_read_post_page
12
13
  Thredded::UrlsHelper.topic_path(@topic, page: page, anchor: anchor)
13
14
  end
15
+
16
+ def reply_path
17
+ Thredded::UrlsHelper.topic_path(@topic, page: last_page, anchor: "new_post")
18
+ end
19
+
20
+ def mark_as_unread_path
21
+ Thredded::UrlsHelper.mark_as_unread_post_path(id: last_post.id, format: :json)
22
+ end
23
+
24
+ def mark_as_read_path
25
+ Thredded::UrlsHelper.mark_as_read_post_path(id: last_post.id, format: :json)
26
+ end
27
+
28
+ def last_page
29
+ (@topic.posts_count / Thredded.posts_per_page.to_f).ceil # TODO: doesn't account for visibility
30
+ end
14
31
  end
15
32
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_dependency File.expand_path("../../app/view_models/thredded/topics_page_view", Thredded::Engine.called_from)
3
4
  module Thredded
4
5
  module TopicsPageViewWithLastPost
@@ -0,0 +1 @@
1
+ <% # overriding thredded's view %>
@@ -0,0 +1,23 @@
1
+ <% if Thredded.show_topic_followers %>
2
+ <%= define_svg_icons "thredded/follow.svg", "thredded/unfollow.svg" %>
3
+ <div class="thredded--topic-followers">
4
+ <% if topic.followers.length > 0 %>
5
+ <%= t('thredded.topics.followed_by')%>
6
+ <% topic.followers.each do |user| %>
7
+ <span class="thredded--follower user-<%= user.id %>">
8
+ <%= user_mention(user) %>
9
+ <%- if user == thredded_current_user %>
10
+ <%= t("thredded.workgroup.following.you")%>
11
+ <%- else %>
12
+ <button class="thredded--follower--remove" data-kick-path="<%= thredded_workgroup.kick_topic_path(topic.to_model.id, user_id: user.id) %>" title="Remove follower" aria-label="Remove follower">
13
+ <%= shared_inline_svg "thredded/follow.svg", class: "thredded--topics--follow-icon", role: "img" %>
14
+ <%= shared_inline_svg "thredded/unfollow.svg", class: "thredded--topics--unfollow-icon", role: "img" %>
15
+ </button>
16
+ <%- end %>
17
+ </span>
18
+ <% end %>
19
+ <% else %>
20
+ <%= t('thredded.topics.followed_by_noone')%>
21
+ <% end %>
22
+ </div>
23
+ <% end %>
@@ -2,22 +2,18 @@
2
2
  id: dom_id(topic),
3
3
  class: ['thredded--topics--topic', topic_css_classes(topic)],
4
4
  data: {topic: topic.id, messageboard: topic.messageboard_id} do %>
5
- <div class="thredded--topics--posts-count"><%= topic.posts_count %></div>
5
+
6
+ <div class="thredded--topic--read-state-toggle">
7
+ <%= shared_inline_svg("thredded/workgroup/envelope-open-o.svg", class: "thredded--topics--read-icon thredded--icon", role: "img", viewBox: "0 0 1792 1792", title: "Mark as read") %>
8
+ <%= shared_inline_svg("thredded/workgroup/envelope-o.svg", class: "thredded--topics--unread-icon thredded--icon", role: "img", viewBox: "0 0 1792 1792", title: "Mark as unread") %>
9
+ </div>
6
10
 
7
11
  <h1 class="thredded--topics--title">
8
12
  <span class="thredded--topic-title"><%= link_to topic.title, topic.path %></span>
9
- <% unless messageboard_or_nil #don't show if being viewed in the context of a messageboard%>
10
- <cite class="thredded--messageboard-name">
11
- <%= link_to topic.messageboard_name, topic.messageboard_path %>
12
- </cite>
13
- <% end %>
14
- <svg viewBox="0 0 116 121" class="thredded--topics--follow-icon">
15
- <% if topic.followed? %>
16
- <use xlink:href="#thredded-follow-icon"/>
17
- <% else %>
18
- <use xlink:href="#thredded-unfollow-icon"/>
19
- <% end %>
20
- </svg>
13
+ <a href="#" class="thredded-follow-toggle js-thredded-follow-toggle">
14
+ <%= shared_inline_svg "thredded/follow.svg", class: "thredded--topics--follow-icon", role: "img" %>
15
+ <%= shared_inline_svg "thredded/unfollow.svg", class: "thredded--topics--unfollow-icon", role: "img" %>
16
+ </a>
21
17
  </h1>
22
18
 
23
19
  <% if topic.categories.any? %>
@@ -26,26 +22,27 @@
26
22
  </ul>
27
23
  <% end %>
28
24
 
25
+ <cite class="thredded--topics--updated-by">
26
+ <%= time_ago topic.last_post_at %>
27
+ <%= user_link topic.last_user %>
28
+ </cite>
29
+
30
+ <% if local_assigns[:show_messageboard] %>
31
+ <span class="thredded--topics--messageboard">
32
+ <%= t 'thredded.topics.in_messageboard_html',
33
+ messageboard_link: link_to(topic.messageboard_name, topic.messageboard_path) %>
34
+ </span>
35
+ <% end %>
29
36
 
30
37
  <% if topic.blocked? && topic.can_moderate? %>
31
38
  <span class="thredded--topics--moderation-state thredded--alert thredded--alert-danger">
32
39
  <%= render 'thredded/shared/content_moderation_blocked_state', moderation_record: topic.last_moderation_record %>
33
40
  </span>
34
41
  <% end %>
42
+ <%= render 'thredded/workgroup/topics/last_post_with_controls', topic: topic if topic.last_post %>
43
+ <% end %>
35
44
 
36
- <%= render partial: 'thredded/topics/followers', locals: {topic: topic} %>
37
-
38
- <div class='thredded--topic-post-and-last-user thredded--condensed'>
39
- <div class="thredded--topic-source">
40
- <cite class="thredded--topics--updated-by">
41
- <%= topic.last_user.thredded_display_name %>
42
- <%= time_ago topic.last_post_at %>
43
- </cite>
44
- </div>
45
-
46
- <div class="thredded--last-post">
47
- <%= render 'thredded/posts_common/content', post: topic.last_post if topic.last_post %>
48
- </div>
49
- </div>
50
-
45
+ <% if local_assigns[:sticky_topics_divider] &&
46
+ !topic_iteration.last? && topic.sticky? && !topics[topic_counter + 1].sticky? %>
47
+ <%= render 'thredded/topics/sticky_topics_divider' %>
51
48
  <% end %>
@@ -1,6 +1,12 @@
1
1
  <ul class="thredded--workgroup">
2
2
  <li class="<%= Thredded::Workgroup.navbar_class(params, :unread) %>">
3
- <%= link_to t('thredded.workgroup.unread.link'), thredded_workgroup.unread_nav_path%>
3
+ <%= link_to thredded_workgroup.unread_nav_path do%>
4
+ <%= t('thredded.workgroup.unread.link') %>
5
+ <% if all_unread_followed_topics_count > 0 -%>
6
+ <span class="thredded--user-navigation--unread-topics--followed-count"><%=shared_inline_svg "thredded/follow.svg", class: "thredded--unread-topics--followed-icon", role:"img" %>
7
+ <%= all_unread_followed_topics_count %></span>
8
+ <% end -%>
9
+ <% end -%>
4
10
  </li>
5
11
  <li class="<%= Thredded::Workgroup.navbar_class(params, :awaiting) %>">
6
12
  <%= link_to thredded_workgroup.awaiting_nav_path do %>
@@ -6,4 +6,4 @@
6
6
  </ul>
7
7
  <% end %>
8
8
 
9
- <%= render partial: 'thredded/topics/topics_with_last_post'%>
9
+ <%= render partial: 'thredded/workgroup/topics/topics_with_last_post'%>
@@ -6,4 +6,4 @@
6
6
  </ul>
7
7
  <% end %>
8
8
 
9
- <%= render partial: 'thredded/topics/topics_with_last_post'%>
9
+ <%= render partial: 'thredded/workgroup/topics/topics_with_last_post'%>
@@ -6,4 +6,4 @@
6
6
  </ul>
7
7
  <% end %>
8
8
 
9
- <%= render partial: 'thredded/topics/topics_with_last_post'%>
9
+ <%= render partial: 'thredded/workgroup/topics/topics_with_last_post'%>
@@ -6,4 +6,4 @@
6
6
  </ul>
7
7
  <% end %>
8
8
 
9
- <%= render partial: 'thredded/topics/topics_with_last_post'%>
9
+ <%= render partial: 'thredded/workgroup/topics/topics_with_last_post'%>
@@ -0,0 +1,21 @@
1
+ <div class="thredded--topic-controls">
2
+ <a class="thredded--topic--read-state-toggle thredded--topic--mark-as-read thredded--button" data-post-path="<%= topic.mark_as_read_path %>">
3
+ <%= shared_inline_svg("thredded/workgroup/envelope-open-o.svg", class: "thredded--topics--read-icon thredded--icon", role: "img", viewBox: "0 0 1792 1792") %>
4
+ <%= t("thredded.topics.mark_read")%>
5
+ </a>
6
+ <a class="thredded--topic--read-state-toggle thredded--topic--mark-as-unread thredded--button" data-post-path="<%= topic.mark_as_unread_path %>">
7
+ <%= shared_inline_svg("thredded/workgroup/envelope-o.svg", class: "thredded--topics--unread-icon thredded--icon", role: "img", viewBox: "0 0 1792 1792") %>
8
+ <%= t("thredded.topics.mark_unread")%>
9
+ </a>
10
+ <a class="thredded--topic--view-button thredded--button" href="<%= topic.reply_path %>">
11
+ <%= t("thredded.topics.view_or_reply")%>
12
+ </a>
13
+ <a href="#" class="js-thredded-follow-toggle thredded--topic--follow thredded--button">
14
+ <%= shared_inline_svg "thredded/follow.svg", class: "thredded--icon", role: "img" %>
15
+ <%= t("thredded.topics.follow")%>
16
+ </a>
17
+ <a href="#" class="js-thredded-follow-toggle thredded--topic--unfollow thredded--button">
18
+ <%= shared_inline_svg "thredded/unfollow.svg", class: "thredded--icon", role: "img" %>
19
+ <%= t("thredded.topics.unfollow")%>
20
+ </a>
21
+ </div>
@@ -0,0 +1,11 @@
1
+ <%= view_hooks.topic_with_last_post.last_post.render self, topic: topic do %>
2
+ <div class="thredded--topic-source">
3
+ <cite class="thredded--topics--updated-by">
4
+ <%= topic.last_user.thredded_display_name %>
5
+ <%= time_ago topic.last_post_at %>
6
+ </cite>
7
+ </div>
8
+ <div class="thredded--last-post">
9
+ <%= render 'thredded/posts_common/content', post: topic.last_post %>
10
+ </div>
11
+ <% end %>
@@ -0,0 +1,12 @@
1
+ <%= view_hooks.topic_with_last_post.last_post_with_controls.render self, topic: topic do %>
2
+ <div class="thredded--topic-last-post-with-controls">
3
+ <%= render "thredded/workgroup/topics/controls", topic: topic %>
4
+ <div class='thredded--topic-post-and-last-user thredded--condensable thredded--condensable--condensed'>
5
+ <%= render "thredded/workgroup/topics/last_post", topic: topic %>
6
+ <div class="thredded--condensable--overflow-only">
7
+ <span class="thredded--condensable--expand"><%= t("thredded.workgroup.condensable.read_all") %></span>
8
+ <span class="thredded--condensable--condense"><%= t("thredded.workgroup.condensable.read_less") %></span>
9
+ </div>
10
+ </div>
11
+ </div>
12
+ <% end %>
@@ -0,0 +1,16 @@
1
+ <%= define_svg_icons 'thredded/follow.svg', 'thredded/unfollow.svg' %>
2
+
3
+ <%= thredded_page do %>
4
+ <%= content_tag :section, class: 'thredded--main-section thredded--topics', 'data-thredded-topics' => true do %>
5
+ <%= render @topics, show_messageboard: !messageboard_or_nil %>
6
+ <% end %>
7
+
8
+ <%= link_to t("thredded.nav.mark_all_read"),
9
+ mark_all_topics_read_path,
10
+ class: 'thredded--button thredded--button-light thredded--button-wide',
11
+ method: :put -%>
12
+
13
+ <footer>
14
+ <%= paginate @topics %>
15
+ </footer>
16
+ <% end %>
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
+
3
4
  # This command will automatically be run when you run "rails"
4
5
  # with Rails 4 gems installed from the root of your application.
5
6
 
data/bin/rspec CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
+
3
4
  #
4
5
  # This file was generated by Bundler.
5
6
  #
@@ -21,6 +21,7 @@ cp -pR $(bundle show thredded)/spec/dummy ./spec/dummy
21
21
 
22
22
  # update some standard helpful files
23
23
  cp $(bundle show thredded)/spec/support/features/fake_content.rb spec/support/features/fake_content.rb
24
+ cp $(bundle show thredded)/spec/lib/thredded/all_view_hooks_spec.rb spec/lib/thredded/all_view_hooks_spec.rb
24
25
 
25
26
  # restore thredded-workgroup config, emoji
26
27
  mv ./tmp/upgradecache/thredded_workgroup.rb ./spec/dummy/config/initializers/