From cf91bca0cd79f4589f1787e2c0a72e37606e471e Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 31 Jul 2015 14:22:28 -0400 Subject: [PATCH] FIX: Small actions should show descriptions on the user stream --- .../discourse/components/small-action.js.es6 | 29 +++++++--------- .../discourse/components/stream-item.js.es6 | 7 ++++ .../controllers/user-activity.js.es6 | 2 +- .../templates/components/small-action.hbs | 5 ++- .../templates/components/stream-item.hbs | 32 +++++++++++++++++ .../discourse/templates/user/stream.hbs | 30 ++-------------- .../views/user-activity-stream.js.es6 | 27 +++++++++++++++ .../discourse/views/user-stream.js.es6 | 6 ++-- app/controllers/user_actions_controller.rb | 2 +- app/models/user_action.rb | 1 + app/models/user_action_observer.rb | 34 +++++++++---------- app/serializers/user_action_serializer.rb | 9 ++--- 12 files changed, 110 insertions(+), 74 deletions(-) create mode 100644 app/assets/javascripts/discourse/components/stream-item.js.es6 create mode 100644 app/assets/javascripts/discourse/templates/components/stream-item.hbs create mode 100644 app/assets/javascripts/discourse/views/user-activity-stream.js.es6 diff --git a/app/assets/javascripts/discourse/components/small-action.js.es6 b/app/assets/javascripts/discourse/components/small-action.js.es6 index 50e42f19ab5..977b408c807 100644 --- a/app/assets/javascripts/discourse/components/small-action.js.es6 +++ b/app/assets/javascripts/discourse/components/small-action.js.es6 @@ -13,27 +13,22 @@ const icons = { 'visible.disabled': 'eye-slash' }; +export function actionDescription(actionCode, createdAt) { + return function() { + const ac = this.get(actionCode); + if (actionCode) { + const dt = new Date(this.get(createdAt)); + const when = Discourse.Formatter.relativeAge(dt, {format: 'medium-with-ago'}); + return I18n.t(`action_codes.${ac}`, {when}).htmlSafe(); + } + }.property(actionCode, createdAt); +} + export default Ember.Component.extend({ layoutName: 'components/small-action', // needed because `time-gap` inherits from this classNames: ['small-action'], - description: function() { - const actionCode = this.get('actionCode'); - if (actionCode) { - const dt = new Date(this.get('post.created_at')); - const when = Discourse.Formatter.relativeAge(dt, {format: 'medium-with-ago'}); - var result = I18n.t(`action_codes.${actionCode}`, {when}); - var cooked = this.get('post.cooked'); - - result = "

" + result + "

"; - - if (!Em.isEmpty(cooked)) { - result += "
" + cooked + "
"; - } - - return result; - } - }.property('actionCode', 'post.created_at', 'post.cooked'), + description: actionDescription('actionCode', 'post.created_at'), icon: function() { return icons[this.get('actionCode')] || 'exclamation'; diff --git a/app/assets/javascripts/discourse/components/stream-item.js.es6 b/app/assets/javascripts/discourse/components/stream-item.js.es6 new file mode 100644 index 00000000000..ef7b03ad5c3 --- /dev/null +++ b/app/assets/javascripts/discourse/components/stream-item.js.es6 @@ -0,0 +1,7 @@ +import { actionDescription } from 'discourse/components/small-action'; + +export default Ember.Component.extend({ + classNameBindings: [':item', 'item.hidden', 'item.deleted', 'moderatorAction'], + moderatorAction: Discourse.computed.propertyEqual('item.post_type', 'site.post_types.moderator_action'), + actionDescription: actionDescription('item.action_code', 'item.created_at') +}); diff --git a/app/assets/javascripts/discourse/controllers/user-activity.js.es6 b/app/assets/javascripts/discourse/controllers/user-activity.js.es6 index 6113cedff3d..7e4ec2db92f 100644 --- a/app/assets/javascripts/discourse/controllers/user-activity.js.es6 +++ b/app/assets/javascripts/discourse/controllers/user-activity.js.es6 @@ -5,7 +5,7 @@ export default Ember.ObjectController.extend({ _showFooter: function() { var showFooter; if (this.get("userActionType")) { - var stat = _.find(this.get("model.stats"), { action_type: this.get("userActionType") }); + const stat = _.find(this.get("model.stats"), { action_type: this.get("userActionType") }); showFooter = stat && stat.count <= this.get("model.stream.itemsLoaded"); } else { showFooter = this.get("model.statsCountNonPM") <= this.get("model.stream.itemsLoaded"); diff --git a/app/assets/javascripts/discourse/templates/components/small-action.hbs b/app/assets/javascripts/discourse/templates/components/small-action.hbs index b05c6580884..091f0e07df2 100644 --- a/app/assets/javascripts/discourse/templates/components/small-action.hbs +++ b/app/assets/javascripts/discourse/templates/components/small-action.hbs @@ -11,5 +11,8 @@ {{avatar post imageSize="small"}} {{/if}} - {{{description}}} +

{{description}}

+ {{#if post.cooked}} +
{{{post.cooked}}}
+ {{/if}} diff --git a/app/assets/javascripts/discourse/templates/components/stream-item.hbs b/app/assets/javascripts/discourse/templates/components/stream-item.hbs new file mode 100644 index 00000000000..8dea1ccb131 --- /dev/null +++ b/app/assets/javascripts/discourse/templates/components/stream-item.hbs @@ -0,0 +1,32 @@ +
+
{{avatar item imageSize="large" extraClasses="actor" ignoreTitle="true"}}
+ {{format-date item.created_at}} + {{topic-status topic=item disableActions=true}} + + {{{item.title}}} + +
{{category-link item.category}}
+
+ +{{#if actionDescription}} +

{{actionDescription}}

+{{/if}} + +

{{{item.excerpt}}}

+ + +{{#each item.children as |child|}} +
+ + {{#each child.items as |grandChild|}} + {{#if grandChild.removableBookmark}} + + {{else}} +
{{avatar grandChild imageSize="tiny" extraClasses="actor" ignoreTitle="true"}}
+ {{#if grandChild.edit_reason}} — {{grandChild.edit_reason}}{{/if}} + {{/if}} + {{/each}} +
+{{/each}} diff --git a/app/assets/javascripts/discourse/templates/user/stream.hbs b/app/assets/javascripts/discourse/templates/user/stream.hbs index 96e96c83768..4f03bef896c 100644 --- a/app/assets/javascripts/discourse/templates/user/stream.hbs +++ b/app/assets/javascripts/discourse/templates/user/stream.hbs @@ -1,29 +1,3 @@ -{{#each item in model.content}} -
-
-
{{avatar item imageSize="large" extraClasses="actor" ignoreTitle="true"}}
- {{format-date item.created_at}} - {{topic-status topic=item disableActions=true}} - - {{{unbound item.title}}} - -
{{category-link item.category}}
-
-

{{{unbound item.excerpt}}}

- {{#each child in item.children}} -
- - {{#each grandChild in child.items}} - {{#if grandChild.removableBookmark}} - - {{else}} -
{{avatar grandChild imageSize="tiny" extraClasses="actor" ignoreTitle="true"}}
- {{#if grandChild.edit_reason}} — {{unbound grandChild.edit_reason}}{{/if}} - {{/if}} - {{/each}} -
- {{/each}} -
+{{#each model.content as |item|}} + {{stream-item item=item}} {{/each}} diff --git a/app/assets/javascripts/discourse/views/user-activity-stream.js.es6 b/app/assets/javascripts/discourse/views/user-activity-stream.js.es6 new file mode 100644 index 00000000000..86fbaefd8f2 --- /dev/null +++ b/app/assets/javascripts/discourse/views/user-activity-stream.js.es6 @@ -0,0 +1,27 @@ +import LoadMore from "discourse/mixins/load-more"; + +export default Ember.View.extend(LoadMore, { + loading: false, + eyelineSelector: '.user-stream .item', + classNames: ['user-stream'], + + _scrollTopOnModelChange: function() { + Em.run.schedule('afterRender', function() { + $(document).scrollTop(0); + }); + }.observes('controller.model.user.id'), + + actions: { + loadMore() { + const self = this; + if (this.get('loading')) { return; } + + this.set('loading', true); + const stream = this.get('controller.model'); + stream.findItems().then(function() { + self.set('loading', false); + self.get('eyeline').flushRest(); + }); + } + } +}); diff --git a/app/assets/javascripts/discourse/views/user-stream.js.es6 b/app/assets/javascripts/discourse/views/user-stream.js.es6 index 367c089ed03..86fbaefd8f2 100644 --- a/app/assets/javascripts/discourse/views/user-stream.js.es6 +++ b/app/assets/javascripts/discourse/views/user-stream.js.es6 @@ -12,12 +12,12 @@ export default Ember.View.extend(LoadMore, { }.observes('controller.model.user.id'), actions: { - loadMore: function() { - var self = this; + loadMore() { + const self = this; if (this.get('loading')) { return; } this.set('loading', true); - var stream = this.get('controller.model'); + const stream = this.get('controller.model'); stream.findItems().then(function() { self.set('loading', false); self.get('eyeline').flushRest(); diff --git a/app/controllers/user_actions_controller.rb b/app/controllers/user_actions_controller.rb index e4d4079fec0..c20f9c8d23d 100644 --- a/app/controllers/user_actions_controller.rb +++ b/app/controllers/user_actions_controller.rb @@ -24,7 +24,7 @@ class UserActionsController < ApplicationController UserAction.stream(opts) end - render_serialized(stream, UserActionSerializer, root: "user_actions") + render_serialized(stream, UserActionSerializer, root: 'user_actions') end def show diff --git a/app/models/user_action.rb b/app/models/user_action.rb index 0d4c661d100..9b72a755dea 100644 --- a/app/models/user_action.rb +++ b/app/models/user_action.rb @@ -154,6 +154,7 @@ SQL CASE WHEN coalesce(p.deleted_at, p2.deleted_at, t.deleted_at) IS NULL THEN false ELSE true END deleted, p.hidden, p.post_type, + p.action_code, p.edit_reason, t.category_id FROM user_actions as a diff --git a/app/models/user_action_observer.rb b/app/models/user_action_observer.rb index 665a1efdfce..34e6fcabedc 100644 --- a/app/models/user_action_observer.rb +++ b/app/models/user_action_observer.rb @@ -29,11 +29,11 @@ class UserActionObserver < ActiveRecord::Observer return unless action && post && user && post.id row = { - action_type: action, - user_id: user.id, - acting_user_id: acting_user_id || post.user_id, - target_topic_id: post.topic_id, - target_post_id: post.id + action_type: action, + user_id: user.id, + acting_user_id: acting_user_id || post.user_id, + target_topic_id: post.topic_id, + target_post_id: post.id } if post.deleted_at.nil? @@ -48,12 +48,12 @@ class UserActionObserver < ActiveRecord::Observer return if model.is_first_post? row = { - action_type: UserAction::REPLY, - user_id: model.user_id, - acting_user_id: model.user_id, - target_post_id: model.id, - target_topic_id: model.topic_id, - created_at: model.created_at + action_type: UserAction::REPLY, + user_id: model.user_id, + acting_user_id: model.user_id, + target_post_id: model.id, + target_topic_id: model.topic_id, + created_at: model.created_at } rows = [row] @@ -79,12 +79,12 @@ class UserActionObserver < ActiveRecord::Observer def log_topic(model) row = { - action_type: model.archetype == Archetype.private_message ? UserAction::NEW_PRIVATE_MESSAGE : UserAction::NEW_TOPIC, - user_id: model.user_id, - acting_user_id: model.user_id, - target_topic_id: model.id, - target_post_id: -1, - created_at: model.created_at + action_type: model.archetype == Archetype.private_message ? UserAction::NEW_PRIVATE_MESSAGE : UserAction::NEW_TOPIC, + user_id: model.user_id, + acting_user_id: model.user_id, + target_topic_id: model.id, + target_post_id: -1, + created_at: model.created_at } rows = [row] diff --git a/app/serializers/user_action_serializer.rb b/app/serializers/user_action_serializer.rb index f6dcf2b9fb3..8b393996392 100644 --- a/app/serializers/user_action_serializer.rb +++ b/app/serializers/user_action_serializer.rb @@ -22,7 +22,8 @@ class UserActionSerializer < ApplicationSerializer :title, :deleted, :hidden, - :moderator_action, + :post_type, + :action_code, :edit_reason, :category_id, :uploaded_avatar_id, @@ -32,7 +33,7 @@ class UserActionSerializer < ApplicationSerializer def excerpt cooked = object.cooked || PrettyText.cook(object.raw) - PrettyText.excerpt(cooked, 300, { keep_emojis: true }) if cooked + PrettyText.excerpt(cooked, 300, keep_emojis: true) if cooked end def avatar_template @@ -67,10 +68,6 @@ class UserActionSerializer < ApplicationSerializer object.title.present? end - def moderator_action - object.post_type == Post.types[:moderator_action] || object.post_type == Post.types[:small_action] - end - def include_reply_to_post_number? object.action_type == UserAction::REPLY end