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 @@
+
+
+{{#if actionDescription}}
+ {{actionDescription}}
+{{/if}}
+
+{{{item.excerpt}}}
+
+
+{{#each item.children as |child|}}
+
+{{/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}}
-
-
-
{{{unbound item.excerpt}}}
- {{#each child in item.children}}
-
- {{/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