UX: Improve interface for flagging with many flaggers
This commit is contained in:
parent
64fae87470
commit
079f108ceb
|
@ -1,6 +1,8 @@
|
||||||
import showModal from 'discourse/lib/show-modal';
|
import showModal from 'discourse/lib/show-modal';
|
||||||
|
|
||||||
export default Ember.Component.extend({
|
export default Ember.Component.extend({
|
||||||
|
expanded: false,
|
||||||
|
|
||||||
tagName: 'div',
|
tagName: 'div',
|
||||||
classNameBindings: [
|
classNameBindings: [
|
||||||
':flagged-post',
|
':flagged-post',
|
||||||
|
@ -36,6 +38,12 @@ export default Ember.Component.extend({
|
||||||
|
|
||||||
defer() {
|
defer() {
|
||||||
this.removeAfter(this.get('flaggedPost').deferFlags());
|
this.removeAfter(this.get('flaggedPost').deferFlags());
|
||||||
|
},
|
||||||
|
|
||||||
|
expand() {
|
||||||
|
this.get('flaggedPost').expandHidden().then(() => {
|
||||||
|
this.set('expanded', true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -66,4 +66,5 @@ export default Post.extend({
|
||||||
postHidden: Ember.computed.alias('hidden'),
|
postHidden: Ember.computed.alias('hidden'),
|
||||||
|
|
||||||
deleted: Ember.computed.or('deleted_at', 'topic_deleted_at'),
|
deleted: Ember.computed.or('deleted_at', 'topic_deleted_at'),
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
<div class='flag-user'>
|
||||||
|
{{#link-to 'adminUser' user.id user.username class='flag-user-avatar'}}
|
||||||
|
{{avatar user imageSize="small"}}
|
||||||
|
{{/link-to}}
|
||||||
|
<div class='flag-user-details'>
|
||||||
|
<div class='flag-user-who'>
|
||||||
|
{{#link-to 'adminUser' user.id user.username class="flag-user-username"}}
|
||||||
|
{{user.username}}
|
||||||
|
{{/link-to}}
|
||||||
|
<div class='flag-user-date'>
|
||||||
|
{{format-age date}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class='flag-user-extra'>
|
||||||
|
{{yield}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -1,5 +1,5 @@
|
||||||
{{#link-to 'adminUser' response.user.id response.user.username class="response-avatar"}}
|
{{#link-to 'adminUser' response.user.id response.user.username class="response-avatar"}}
|
||||||
{{avatar response.user imageSize="medium"}}
|
{{avatar response.user imageSize="small"}}
|
||||||
{{/link-to}}
|
{{/link-to}}
|
||||||
<div class='excerpt'>{{{response.excerpt}}}</div>
|
<div class='excerpt'>{{{response.excerpt}}}</div>
|
||||||
{{#if hasMore}}
|
{{#if hasMore}}
|
||||||
|
|
|
@ -17,134 +17,126 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flagged-post-excerpt">
|
<div class="flagged-post-contents">
|
||||||
{{#unless hideTitle}}
|
<div class='flagged-post-excerpt'>
|
||||||
<h3>
|
{{#unless hideTitle}}
|
||||||
{{#if flaggedPost.topic.isPrivateMessage}}
|
<h3>
|
||||||
<span class="private-message-glyph">{{d-icon "envelope"}}</span>
|
{{#if flaggedPost.topic.isPrivateMessage}}
|
||||||
|
<span class="private-message-glyph">{{d-icon "envelope"}}</span>
|
||||||
|
{{/if}}
|
||||||
|
{{topic-status topic=flaggedPost.topic}}
|
||||||
|
<a href='{{unbound flaggedPost.url}}'>{{{unbound flaggedPost.topic.fancyTitle}}}</a>
|
||||||
|
</h3>
|
||||||
|
{{/unless}}
|
||||||
|
{{#if flaggedPost.postAuthorFlagged}}
|
||||||
|
{{#if expanded}}
|
||||||
|
{{{flaggedPost.cooked}}}
|
||||||
|
{{else}}
|
||||||
|
<p>
|
||||||
|
{{{flaggedPost.excerpt}}}
|
||||||
|
<a href {{action "expand"}}>{{i18n "admin.flags.show_full"}}</a>
|
||||||
|
</p>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{topic-status topic=flaggedPost.topic}}
|
{{/if}}
|
||||||
<a href='{{unbound flaggedPost.url}}'>{{{unbound flaggedPost.topic.fancyTitle}}}</a>
|
</div>
|
||||||
</h3>
|
|
||||||
{{/unless}}
|
|
||||||
{{#if flaggedPost.postAuthorFlagged}}
|
|
||||||
<p>{{{flaggedPost.excerpt}}}</p>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class='flaggers'>
|
{{#if flaggedPost.topicFlagged}}
|
||||||
{{#if site.mobileView}}
|
<div class='flagged-post-message'>
|
||||||
<div class='flaggers-title'>
|
<span class='text'>{{{i18n 'admin.flags.topic_flagged'}}}</span>
|
||||||
{{i18n 'admin.flags.flagged_by'}}
|
<a href={{flaggedPost.url}} class="btn">{{i18n 'admin.flags.visit_topic'}}</a>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#each flaggedPost.post_actions as |postAction|}}
|
{{#each flaggedPost.conversations as |c|}}
|
||||||
<div class='flagger'>
|
<div class='flag-conversation'>
|
||||||
{{#link-to 'adminUser' postAction.user.id postAction.user.username class='flagger-avatar'}}
|
{{#if c.response}}
|
||||||
{{avatar postAction.user imageSize="medium"}}
|
{{flagged-post-response response=c.response}}
|
||||||
{{/link-to}}
|
{{#if c.reply}}
|
||||||
<div class='flagger-details'>
|
{{flagged-post-response response=c.reply hasMore=c.hasMore permalink=c.permalink}}
|
||||||
<div class='flagger-username'>
|
{{/if}}
|
||||||
{{#link-to 'adminUser' postAction.user.id postAction.user.username}}
|
<a href={{c.permalink}} class="btn reply-conversation btn-small">
|
||||||
{{postAction.user.username}}
|
{{d-icon "reply"}}
|
||||||
{{/link-to}}
|
{{i18n "admin.flags.reply_message"}}
|
||||||
</div>
|
</a>
|
||||||
<div class='flagger-flagged-at'>
|
{{/if}}
|
||||||
{{format-age postAction.created_at}}
|
|
||||||
</div>
|
|
||||||
<div class='flagger-flag-type'>
|
|
||||||
{{i18n (concat "admin.flags.summary.action_type_" postAction.post_action_type_id) count=1}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
|
||||||
|
|
||||||
{{#if showResolvedBy}}
|
<div class='flag-user-lists'>
|
||||||
<div class='flagged-post-resolved-by'>
|
<div class='flagged-by'>
|
||||||
{{#each flaggedPost.post_actions as |postAction|}}
|
<div class='user-list-title'>
|
||||||
<div class='disposer'>
|
{{i18n "admin.flags.flagged_by"}}
|
||||||
{{#link-to
|
</div>
|
||||||
'adminUser'
|
<div class='flag-users'>
|
||||||
postAction.disposed_by.id
|
{{#each flaggedPost.post_actions as |postAction|}}
|
||||||
postAction.disposed_by.username
|
{{#flag-user user=postAction.user date=postAction.created_at}}
|
||||||
class="disposer-avatar"}}
|
<div class='flagger-flag-type'>
|
||||||
{{avatar postAction.disposed_by imageSize="medium"}}
|
{{i18n (concat "admin.flags.summary.action_type_" postAction.post_action_type_id) count=1}}
|
||||||
{{/link-to}}
|
</div>
|
||||||
<div class='disposer-details'>
|
{{/flag-user}}
|
||||||
{{format-age postAction.disposed_at}}
|
{{/each}}
|
||||||
{{disposition-icon postAction.disposition}}
|
</div>
|
||||||
{{#if postAction.staff_took_action}}
|
</div>
|
||||||
{{d-icon "gavel" title="admin.flags.took_action"}}
|
|
||||||
{{/if}}
|
{{#if showResolvedBy}}
|
||||||
|
<div class='flagged-post-resolved-by'>
|
||||||
|
<div class='user-list-title'>
|
||||||
|
{{i18n "admin.flags.resolved_by"}}
|
||||||
|
</div>
|
||||||
|
<div class='flag-users'>
|
||||||
|
{{#each flaggedPost.post_actions as |postAction|}}
|
||||||
|
{{#flag-user user=postAction.disposed_by date=postAction.disposed_at}}
|
||||||
|
{{disposition-icon postAction.disposition}}
|
||||||
|
{{#if postAction.staff_took_action}}
|
||||||
|
{{d-icon "gavel" title="admin.flags.took_action"}}
|
||||||
|
{{/if}}
|
||||||
|
{{/flag-user}}
|
||||||
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{#if flaggedPost.topicFlagged}}
|
|
||||||
<div class='flagged-post-message'>
|
|
||||||
<span class='text'>{{{i18n 'admin.flags.topic_flagged'}}}</span>
|
|
||||||
<a href={{flaggedPost.url}} class="btn">{{i18n 'admin.flags.visit_topic'}}</a>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#each flaggedPost.conversations as |c|}}
|
|
||||||
<div class='flagged-post-message'>
|
|
||||||
{{#if c.response}}
|
|
||||||
{{flagged-post-response response=c.response}}
|
|
||||||
{{#if c.reply}}
|
|
||||||
{{flagged-post-response response=c.reply hasMore=c.hasMore permalink=c.permalink}}
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<a href={{c.permalink}} class="btn btn-reply">
|
</div>
|
||||||
{{d-icon "reply"}}
|
|
||||||
{{i18n "admin.flags.reply_message"}}
|
{{#if canAct}}
|
||||||
</a>
|
<div class='flagged-post-controls'>
|
||||||
|
{{d-button
|
||||||
|
title="admin.flags.agree_title"
|
||||||
|
class="agree-flag"
|
||||||
|
label="admin.flags.agree"
|
||||||
|
icon="thumbs-o-up"
|
||||||
|
action="showAgreeFlagModal"
|
||||||
|
ellipsis=true}}
|
||||||
|
|
||||||
|
{{#if flaggedPost.postHidden}}
|
||||||
|
{{d-button
|
||||||
|
title="admin.flags.disagree_flag_unhide_post_title"
|
||||||
|
class="disagree-flag"
|
||||||
|
action="disagree"
|
||||||
|
icon="thumbs-o-down"
|
||||||
|
label="admin.flags.disagree_flag_unhide_post"}}
|
||||||
|
{{else}}
|
||||||
|
{{d-button
|
||||||
|
title="admin.flags.disagree_flag_title"
|
||||||
|
class="disagree-flag"
|
||||||
|
action="disagree"
|
||||||
|
icon="thumbs-o-down"
|
||||||
|
label="admin.flags.disagree_flag"}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{d-button
|
||||||
|
class="defer-flag"
|
||||||
|
title="admin.flags.defer_flag_title"
|
||||||
|
action="defer"
|
||||||
|
icon="external-link"
|
||||||
|
label="admin.flags.defer_flag"}}
|
||||||
|
|
||||||
|
{{d-button
|
||||||
|
class="btn-danger delete-flag"
|
||||||
|
title="admin.flags.delete_title"
|
||||||
|
action="showDeleteFlagModal"
|
||||||
|
icon="trash-o"
|
||||||
|
label="admin.flags.delete"}}
|
||||||
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
</div>
|
||||||
|
|
||||||
{{#if canAct}}
|
|
||||||
<div class='flagged-post-controls'>
|
|
||||||
{{d-button
|
|
||||||
title="admin.flags.agree_title"
|
|
||||||
class="agree-flag"
|
|
||||||
label="admin.flags.agree"
|
|
||||||
icon="thumbs-o-up"
|
|
||||||
action="showAgreeFlagModal"
|
|
||||||
ellipsis=true}}
|
|
||||||
|
|
||||||
{{#if flaggedPost.postHidden}}
|
|
||||||
{{d-button
|
|
||||||
title="admin.flags.disagree_flag_unhide_post_title"
|
|
||||||
class="disagree-flag"
|
|
||||||
action="disagree"
|
|
||||||
icon="thumbs-o-down"
|
|
||||||
label="admin.flags.disagree_flag_unhide_post"}}
|
|
||||||
{{else}}
|
|
||||||
{{d-button
|
|
||||||
title="admin.flags.disagree_flag_title"
|
|
||||||
class="disagree-flag"
|
|
||||||
action="disagree"
|
|
||||||
icon="thumbs-o-down"
|
|
||||||
label="admin.flags.disagree_flag"}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{d-button
|
|
||||||
class="defer-flag"
|
|
||||||
title="admin.flags.defer_flag_title"
|
|
||||||
action="defer"
|
|
||||||
icon="external-link"
|
|
||||||
label="admin.flags.defer_flag"}}
|
|
||||||
|
|
||||||
{{d-button
|
|
||||||
class="btn-danger delete-flag"
|
|
||||||
title="admin.flags.delete_title"
|
|
||||||
action="showDeleteFlagModal"
|
|
||||||
icon="trash-o"
|
|
||||||
label="admin.flags.delete"}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
|
@ -1,14 +1,5 @@
|
||||||
{{#if flaggedPosts}}
|
{{#if flaggedPosts}}
|
||||||
{{#load-more selector=".flagged-post" action=(action "loadMore")}}
|
{{#load-more selector=".flagged-post" action=(action "loadMore")}}
|
||||||
<div class='flagged-posts-header'>
|
|
||||||
<div class='flagged-by-header'>
|
|
||||||
{{i18n 'admin.flags.flagged_by'}}
|
|
||||||
</div>
|
|
||||||
{{#if showResolvedBy}}
|
|
||||||
{{i18n 'admin.flags.resolved_by'}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class='flagged-posts'>
|
<div class='flagged-posts'>
|
||||||
{{#each flaggedPosts as |flaggedPost|}}
|
{{#each flaggedPosts as |flaggedPost|}}
|
||||||
{{flagged-post
|
{{flagged-post
|
||||||
|
|
|
@ -53,7 +53,11 @@ const Post = RestModel.extend({
|
||||||
}.property('firstPost', 'deleted_at', 'topic.deleted_at'),
|
}.property('firstPost', 'deleted_at', 'topic.deleted_at'),
|
||||||
|
|
||||||
url: function() {
|
url: function() {
|
||||||
return postUrl(this.get('topic.slug') || this.get('topic_slug'), this.get('topic_id'), this.get('post_number'));
|
return postUrl(
|
||||||
|
this.get('topic.slug') || this.get('topic_slug'),
|
||||||
|
this.get('topic_id') || this.get('topic.id'),
|
||||||
|
this.get('post_number')
|
||||||
|
);
|
||||||
}.property('post_number', 'topic_id', 'topic.slug'),
|
}.property('post_number', 'topic_id', 'topic.slug'),
|
||||||
|
|
||||||
// Don't drop the /1
|
// Don't drop the /1
|
||||||
|
|
|
@ -1,15 +1,3 @@
|
||||||
.flagged-posts-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
|
|
||||||
font-weight: bold;
|
|
||||||
.flagged-by-header {
|
|
||||||
width: 12em;
|
|
||||||
}
|
|
||||||
padding-bottom: 0.5em;
|
|
||||||
border-bottom: 1px solid $primary-low;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flagged-post.hidden-post {
|
.flagged-post.hidden-post {
|
||||||
.flagged-post-excerpt, .flagged-post-avatar {
|
.flagged-post-excerpt, .flagged-post-avatar {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
|
@ -23,12 +11,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.flagged-post {
|
.flagged-post {
|
||||||
padding: 1em 0 0 0;
|
padding: 1em 0 0.55em 0;
|
||||||
border-bottom: 1px solid $primary-low;
|
border-bottom: 1px solid $primary-low;
|
||||||
|
|
||||||
.flagged-post-details {
|
.flagged-post-details {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
.flagged-post-avatar {
|
.flagged-post-avatar {
|
||||||
margin-right: 1em;
|
margin-right: 1em;
|
||||||
|
@ -46,9 +33,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.flagged-post-excerpt {
|
.flagged-post-contents {
|
||||||
min-width: 70%;
|
|
||||||
width: 80%;
|
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
.d-icon {
|
.d-icon {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
@ -64,26 +49,53 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.flagger {
|
.flag-user-lists {
|
||||||
width: 12em;
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-list-title {
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flag-users {
|
||||||
|
margin: 0.5em 0;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flag-user {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
|
margin-right: 2em;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.flag-user-who {
|
||||||
|
display: flex;
|
||||||
|
width: 13em;
|
||||||
|
}
|
||||||
|
.flag-user-username {
|
||||||
|
font-weight: bold;
|
||||||
|
margin-right: 0.5em;
|
||||||
|
}
|
||||||
|
.flag-user-date {
|
||||||
|
color: $primary-medium;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flag-user-avatar {
|
||||||
|
margin-right: 0.5em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.flagger-avatar, .disposer-avatar {
|
.flag-conversation {
|
||||||
margin-right: 1em;
|
padding: 1em;
|
||||||
min-width: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.disposer {
|
.reply-conversation {
|
||||||
width: 7em;
|
margin-left: 32px;
|
||||||
justify-content: flex-end;
|
}
|
||||||
display: flex;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flagged-post-resolved-by {
|
|
||||||
width: 12em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.flagged-post-message {
|
.flagged-post-message {
|
||||||
|
@ -117,7 +129,6 @@
|
||||||
.flagged-post-controls {
|
.flagged-post-controls {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: flex-end;
|
|
||||||
|
|
||||||
button {
|
button {
|
||||||
margin-right: 0.5em;
|
margin-right: 0.5em;
|
||||||
|
@ -164,9 +175,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobile-view {
|
.mobile-view {
|
||||||
.flagged-posts-header {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.flagged-posts {
|
.flagged-posts {
|
||||||
.flagged-post-details {
|
.flagged-post-details {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
@ -180,11 +188,6 @@
|
||||||
width: 70%;
|
width: 70%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flaggers-title {
|
|
||||||
font-weight: bold;
|
|
||||||
margin: 0.5em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flaggers {
|
.flaggers {
|
||||||
margin-left: 4em;
|
margin-left: 4em;
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
|
|
|
@ -2641,6 +2641,7 @@ en:
|
||||||
reply_message: "Reply"
|
reply_message: "Reply"
|
||||||
no_results: "There are no flaged posts."
|
no_results: "There are no flaged posts."
|
||||||
topic_flagged: "This <strong>topic</strong> has been flagged."
|
topic_flagged: "This <strong>topic</strong> has been flagged."
|
||||||
|
show_full: "show full post"
|
||||||
visit_topic: "Visit the topic to take action"
|
visit_topic: "Visit the topic to take action"
|
||||||
was_edited: "Post was edited after the first flag"
|
was_edited: "Post was edited after the first flag"
|
||||||
previous_flags_count: "This post has already been flagged {{count}} times."
|
previous_flags_count: "This post has already been flagged {{count}} times."
|
||||||
|
|
|
@ -5,7 +5,7 @@ QUnit.test("flagged posts", assert => {
|
||||||
visit("/admin/flags/active");
|
visit("/admin/flags/active");
|
||||||
andThen(() => {
|
andThen(() => {
|
||||||
assert.equal(find('.flagged-posts .flagged-post').length, 1);
|
assert.equal(find('.flagged-posts .flagged-post').length, 1);
|
||||||
assert.equal(find('.flagged-post .flaggers .flagger').length, 1, 'shows who flagged it');
|
assert.equal(find('.flagged-post .flag-user').length, 1, 'shows who flagged it');
|
||||||
assert.equal(find('.flagged-post-response').length, 2);
|
assert.equal(find('.flagged-post-response').length, 2);
|
||||||
assert.equal(find('.flagged-post-response:eq(0) img.avatar').length, 1);
|
assert.equal(find('.flagged-post-response:eq(0) img.avatar').length, 1);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue