FIX: Small actions should show descriptions on the user stream
This commit is contained in:
parent
d71301e406
commit
cf91bca0cd
|
@ -13,27 +13,22 @@ const icons = {
|
||||||
'visible.disabled': 'eye-slash'
|
'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({
|
export default Ember.Component.extend({
|
||||||
layoutName: 'components/small-action', // needed because `time-gap` inherits from this
|
layoutName: 'components/small-action', // needed because `time-gap` inherits from this
|
||||||
classNames: ['small-action'],
|
classNames: ['small-action'],
|
||||||
|
|
||||||
description: function() {
|
description: actionDescription('actionCode', 'post.created_at'),
|
||||||
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 = "<p>" + result + "</p>";
|
|
||||||
|
|
||||||
if (!Em.isEmpty(cooked)) {
|
|
||||||
result += "<div class='custom-message'>" + cooked + "</div>";
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}.property('actionCode', 'post.created_at', 'post.cooked'),
|
|
||||||
|
|
||||||
icon: function() {
|
icon: function() {
|
||||||
return icons[this.get('actionCode')] || 'exclamation';
|
return icons[this.get('actionCode')] || 'exclamation';
|
||||||
|
|
|
@ -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')
|
||||||
|
});
|
|
@ -5,7 +5,7 @@ export default Ember.ObjectController.extend({
|
||||||
_showFooter: function() {
|
_showFooter: function() {
|
||||||
var showFooter;
|
var showFooter;
|
||||||
if (this.get("userActionType")) {
|
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");
|
showFooter = stat && stat.count <= this.get("model.stream.itemsLoaded");
|
||||||
} else {
|
} else {
|
||||||
showFooter = this.get("model.statsCountNonPM") <= this.get("model.stream.itemsLoaded");
|
showFooter = this.get("model.statsCountNonPM") <= this.get("model.stream.itemsLoaded");
|
||||||
|
|
|
@ -11,5 +11,8 @@
|
||||||
{{avatar post imageSize="small"}}
|
{{avatar post imageSize="small"}}
|
||||||
</a>
|
</a>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{{description}}}
|
<p>{{description}}</p>
|
||||||
|
{{#if post.cooked}}
|
||||||
|
<div class='custom-message'>{{{post.cooked}}}</div>
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
<div class='clearfix info'>
|
||||||
|
<a href={{item.userUrl}} data-user-card={{item.username}} class='avatar-link'><div class='avatar-wrapper'>{{avatar item imageSize="large" extraClasses="actor" ignoreTitle="true"}}</div></a>
|
||||||
|
<span class='time'>{{format-date item.created_at}}</span>
|
||||||
|
{{topic-status topic=item disableActions=true}}
|
||||||
|
<span class="title">
|
||||||
|
<a href={{item.postUrl}}>{{{item.title}}}</a>
|
||||||
|
</span>
|
||||||
|
<div class="category">{{category-link item.category}}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if actionDescription}}
|
||||||
|
<p class='excerpt'>{{actionDescription}}</p>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<p class='excerpt'>{{{item.excerpt}}}</p>
|
||||||
|
|
||||||
|
|
||||||
|
{{#each item.children as |child|}}
|
||||||
|
<div class='child-actions'>
|
||||||
|
<i class="icon {{child.icon}}"></i>
|
||||||
|
{{#each child.items as |grandChild|}}
|
||||||
|
{{#if grandChild.removableBookmark}}
|
||||||
|
<button class="btn btn-default remove-bookmark" {{action "removeBookmark" grandChild}}>
|
||||||
|
{{fa-icon 'times'}} {{i18n "bookmarks.remove"}}
|
||||||
|
</button>
|
||||||
|
{{else}}
|
||||||
|
<a href={{grandChild.userUrl}} data-user-card={{grandChild.username}} class='avatar-link'><div class='avatar-wrapper'>{{avatar grandChild imageSize="tiny" extraClasses="actor" ignoreTitle="true"}}</div></a>
|
||||||
|
{{#if grandChild.edit_reason}} — <span class="edit-reason">{{grandChild.edit_reason}}</span>{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
|
@ -1,29 +1,3 @@
|
||||||
{{#each item in model.content}}
|
{{#each model.content as |item|}}
|
||||||
<div {{bind-attr class=":item item.hidden item.deleted item.moderator_action"}}>
|
{{stream-item item=item}}
|
||||||
<div class='clearfix info'>
|
|
||||||
<a href="{{unbound item.userUrl}}" data-user-card="{{unbound item.username}}" class='avatar-link'><div class='avatar-wrapper'>{{avatar item imageSize="large" extraClasses="actor" ignoreTitle="true"}}</div></a>
|
|
||||||
<span class='time'>{{format-date item.created_at}}</span>
|
|
||||||
{{topic-status topic=item disableActions=true}}
|
|
||||||
<span class="title">
|
|
||||||
<a href="{{unbound item.postUrl}}">{{{unbound item.title}}}</a>
|
|
||||||
</span>
|
|
||||||
<div class="category">{{category-link item.category}}</div>
|
|
||||||
</div>
|
|
||||||
<p class='excerpt'>{{{unbound item.excerpt}}}</p>
|
|
||||||
{{#each child in item.children}}
|
|
||||||
<div class='child-actions'>
|
|
||||||
<i class="icon {{unbound child.icon}}"></i>
|
|
||||||
{{#each grandChild in child.items}}
|
|
||||||
{{#if grandChild.removableBookmark}}
|
|
||||||
<button class="btn btn-default remove-bookmark" {{action "removeBookmark" grandChild}}>
|
|
||||||
{{fa-icon 'times'}} {{i18n "bookmarks.remove"}}
|
|
||||||
</button>
|
|
||||||
{{else}}
|
|
||||||
<a href="{{unbound grandChild.userUrl}}" data-user-card="{{unbound grandChild.username}}" class='avatar-link'><div class='avatar-wrapper'>{{avatar grandChild imageSize="tiny" extraClasses="actor" ignoreTitle="true"}}</div></a>
|
|
||||||
{{#if grandChild.edit_reason}} — <span class="edit-reason">{{unbound grandChild.edit_reason}}</span>{{/if}}
|
|
||||||
{{/if}}
|
|
||||||
{{/each}}
|
|
||||||
</div>
|
|
||||||
{{/each}}
|
|
||||||
</div>
|
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
|
@ -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();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -12,12 +12,12 @@ export default Ember.View.extend(LoadMore, {
|
||||||
}.observes('controller.model.user.id'),
|
}.observes('controller.model.user.id'),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
loadMore: function() {
|
loadMore() {
|
||||||
var self = this;
|
const self = this;
|
||||||
if (this.get('loading')) { return; }
|
if (this.get('loading')) { return; }
|
||||||
|
|
||||||
this.set('loading', true);
|
this.set('loading', true);
|
||||||
var stream = this.get('controller.model');
|
const stream = this.get('controller.model');
|
||||||
stream.findItems().then(function() {
|
stream.findItems().then(function() {
|
||||||
self.set('loading', false);
|
self.set('loading', false);
|
||||||
self.get('eyeline').flushRest();
|
self.get('eyeline').flushRest();
|
||||||
|
|
|
@ -24,7 +24,7 @@ class UserActionsController < ApplicationController
|
||||||
UserAction.stream(opts)
|
UserAction.stream(opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
render_serialized(stream, UserActionSerializer, root: "user_actions")
|
render_serialized(stream, UserActionSerializer, root: 'user_actions')
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
|
|
|
@ -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,
|
CASE WHEN coalesce(p.deleted_at, p2.deleted_at, t.deleted_at) IS NULL THEN false ELSE true END deleted,
|
||||||
p.hidden,
|
p.hidden,
|
||||||
p.post_type,
|
p.post_type,
|
||||||
|
p.action_code,
|
||||||
p.edit_reason,
|
p.edit_reason,
|
||||||
t.category_id
|
t.category_id
|
||||||
FROM user_actions as a
|
FROM user_actions as a
|
||||||
|
|
|
@ -29,11 +29,11 @@ class UserActionObserver < ActiveRecord::Observer
|
||||||
return unless action && post && user && post.id
|
return unless action && post && user && post.id
|
||||||
|
|
||||||
row = {
|
row = {
|
||||||
action_type: action,
|
action_type: action,
|
||||||
user_id: user.id,
|
user_id: user.id,
|
||||||
acting_user_id: acting_user_id || post.user_id,
|
acting_user_id: acting_user_id || post.user_id,
|
||||||
target_topic_id: post.topic_id,
|
target_topic_id: post.topic_id,
|
||||||
target_post_id: post.id
|
target_post_id: post.id
|
||||||
}
|
}
|
||||||
|
|
||||||
if post.deleted_at.nil?
|
if post.deleted_at.nil?
|
||||||
|
@ -48,12 +48,12 @@ class UserActionObserver < ActiveRecord::Observer
|
||||||
return if model.is_first_post?
|
return if model.is_first_post?
|
||||||
|
|
||||||
row = {
|
row = {
|
||||||
action_type: UserAction::REPLY,
|
action_type: UserAction::REPLY,
|
||||||
user_id: model.user_id,
|
user_id: model.user_id,
|
||||||
acting_user_id: model.user_id,
|
acting_user_id: model.user_id,
|
||||||
target_post_id: model.id,
|
target_post_id: model.id,
|
||||||
target_topic_id: model.topic_id,
|
target_topic_id: model.topic_id,
|
||||||
created_at: model.created_at
|
created_at: model.created_at
|
||||||
}
|
}
|
||||||
|
|
||||||
rows = [row]
|
rows = [row]
|
||||||
|
@ -79,12 +79,12 @@ class UserActionObserver < ActiveRecord::Observer
|
||||||
|
|
||||||
def log_topic(model)
|
def log_topic(model)
|
||||||
row = {
|
row = {
|
||||||
action_type: model.archetype == Archetype.private_message ? UserAction::NEW_PRIVATE_MESSAGE : UserAction::NEW_TOPIC,
|
action_type: model.archetype == Archetype.private_message ? UserAction::NEW_PRIVATE_MESSAGE : UserAction::NEW_TOPIC,
|
||||||
user_id: model.user_id,
|
user_id: model.user_id,
|
||||||
acting_user_id: model.user_id,
|
acting_user_id: model.user_id,
|
||||||
target_topic_id: model.id,
|
target_topic_id: model.id,
|
||||||
target_post_id: -1,
|
target_post_id: -1,
|
||||||
created_at: model.created_at
|
created_at: model.created_at
|
||||||
}
|
}
|
||||||
|
|
||||||
rows = [row]
|
rows = [row]
|
||||||
|
|
|
@ -22,7 +22,8 @@ class UserActionSerializer < ApplicationSerializer
|
||||||
:title,
|
:title,
|
||||||
:deleted,
|
:deleted,
|
||||||
:hidden,
|
:hidden,
|
||||||
:moderator_action,
|
:post_type,
|
||||||
|
:action_code,
|
||||||
:edit_reason,
|
:edit_reason,
|
||||||
:category_id,
|
:category_id,
|
||||||
:uploaded_avatar_id,
|
:uploaded_avatar_id,
|
||||||
|
@ -32,7 +33,7 @@ class UserActionSerializer < ApplicationSerializer
|
||||||
|
|
||||||
def excerpt
|
def excerpt
|
||||||
cooked = object.cooked || PrettyText.cook(object.raw)
|
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
|
end
|
||||||
|
|
||||||
def avatar_template
|
def avatar_template
|
||||||
|
@ -67,10 +68,6 @@ class UserActionSerializer < ApplicationSerializer
|
||||||
object.title.present?
|
object.title.present?
|
||||||
end
|
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?
|
def include_reply_to_post_number?
|
||||||
object.action_type == UserAction::REPLY
|
object.action_type == UserAction::REPLY
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue