Use small actions for moving posts

This commit is contained in:
Robin Ward 2015-07-31 16:30:18 -04:00
parent cf91bca0cd
commit 76aa0795b3
12 changed files with 88 additions and 89 deletions

View File

@ -10,7 +10,8 @@ const icons = {
'pinned_globally.enabled': 'thumb-tack', 'pinned_globally.enabled': 'thumb-tack',
'pinned_globally.disabled': 'thumb-tack unpinned', 'pinned_globally.disabled': 'thumb-tack unpinned',
'visible.enabled': 'eye', 'visible.enabled': 'eye',
'visible.disabled': 'eye-slash' 'visible.disabled': 'eye-slash',
'split_topic': 'sign-out'
}; };
export function actionDescription(actionCode, createdAt) { export function actionDescription(actionCode, createdAt) {

View File

@ -1,12 +1,15 @@
import Presence from 'discourse/mixins/presence'; import Presence from 'discourse/mixins/presence';
import SelectedPostsCount from 'discourse/mixins/selected-posts-count'; import SelectedPostsCount from 'discourse/mixins/selected-posts-count';
import ModalFunctionality from 'discourse/mixins/modal-functionality'; import ModalFunctionality from 'discourse/mixins/modal-functionality';
import ObjectController from 'discourse/controllers/object'; import { movePosts, mergeTopic } from 'discourse/models/topic';
// Modal related to merging of topics // Modal related to merging of topics
export default ObjectController.extend(SelectedPostsCount, ModalFunctionality, Presence, { export default Ember.Controller.extend(SelectedPostsCount, ModalFunctionality, Presence, {
needs: ['topic'], needs: ['topic'],
saving: false,
selectedTopicId: null,
topicController: Em.computed.alias('controllers.topic'), topicController: Em.computed.alias('controllers.topic'),
selectedPosts: Em.computed.alias('topicController.selectedPosts'), selectedPosts: Em.computed.alias('topicController.selectedPosts'),
selectedReplies: Em.computed.alias('topicController.selectedReplies'), selectedReplies: Em.computed.alias('topicController.selectedReplies'),
@ -22,38 +25,40 @@ export default ObjectController.extend(SelectedPostsCount, ModalFunctionality, P
return I18n.t('topic.merge_topic.title'); return I18n.t('topic.merge_topic.title');
}.property('saving'), }.property('saving'),
onShow: function() { onShow() {
this.set('controllers.modal.modalClass', 'split-modal'); this.set('controllers.modal.modalClass', 'split-modal');
}, },
actions: { actions: {
movePostsToExistingTopic: function() { movePostsToExistingTopic() {
const topicId = this.get('model.id');
this.set('saving', true); this.set('saving', true);
var promise = null; let promise = null;
if (this.get('allPostsSelected')) { if (this.get('allPostsSelected')) {
promise = Discourse.Topic.mergeTopic(this.get('id'), this.get('selectedTopicId')); promise = mergeTopic(topicId, this.get('selectedTopicId'));
} else { } else {
var postIds = this.get('selectedPosts').map(function(p) { return p.get('id'); }), const postIds = this.get('selectedPosts').map(function(p) { return p.get('id'); });
replyPostIds = this.get('selectedReplies').map(function(p) { return p.get('id'); }); const replyPostIds = this.get('selectedReplies').map(function(p) { return p.get('id'); });
promise = Discourse.Topic.movePosts(this.get('id'), { promise = movePosts(topicId, {
destination_topic_id: this.get('selectedTopicId'), destination_topic_id: this.get('selectedTopicId'),
post_ids: postIds, post_ids: postIds,
reply_post_ids: replyPostIds reply_post_ids: replyPostIds
}); });
} }
var mergeTopicController = this; const self = this;
promise.then(function(result) { promise.then(function(result) {
// Posts moved // Posts moved
mergeTopicController.send('closeModal'); self.send('closeModal');
mergeTopicController.get('topicController').send('toggleMultiSelect'); self.get('topicController').send('toggleMultiSelect');
Em.run.next(function() { Discourse.URL.routeTo(result.url); }); Em.run.next(function() { Discourse.URL.routeTo(result.url); });
}, function() { }).catch(function() {
// Error moving posts self.flash(I18n.t('topic.merge_topic.error'));
mergeTopicController.flash(I18n.t('topic.merge_topic.error')); }).finally(function() {
mergeTopicController.set('saving', false); self.set('saving', false);
}); });
return false; return false;
} }

View File

@ -1,15 +1,20 @@
import Presence from 'discourse/mixins/presence'; import Presence from 'discourse/mixins/presence';
import SelectedPostsCount from 'discourse/mixins/selected-posts-count'; import SelectedPostsCount from 'discourse/mixins/selected-posts-count';
import ModalFunctionality from 'discourse/mixins/modal-functionality'; import ModalFunctionality from 'discourse/mixins/modal-functionality';
import ObjectController from 'discourse/controllers/object'; import { extractError } from 'discourse/lib/ajax-error';
import { movePosts } from 'discourse/models/topic';
// Modal related to auto closing of topics // Modal related to auto closing of topics
export default ObjectController.extend(SelectedPostsCount, ModalFunctionality, Presence, { export default Ember.Controller.extend(SelectedPostsCount, ModalFunctionality, Presence, {
needs: ['topic'], needs: ['topic'],
topicName: null,
saving: false,
categoryId: null,
topicController: Em.computed.alias('controllers.topic'), topicController: Em.computed.alias('controllers.topic'),
selectedPosts: Em.computed.alias('topicController.selectedPosts'), selectedPosts: Em.computed.alias('topicController.selectedPosts'),
selectedReplies: Em.computed.alias('topicController.selectedReplies'), selectedReplies: Em.computed.alias('topicController.selectedReplies'),
allPostsSelected: Em.computed.alias('topicController.allPostsSelected'),
buttonDisabled: function() { buttonDisabled: function() {
if (this.get('saving')) return true; if (this.get('saving')) return true;
@ -21,7 +26,7 @@ export default ObjectController.extend(SelectedPostsCount, ModalFunctionality, P
return I18n.t('topic.split_topic.action'); return I18n.t('topic.split_topic.action');
}.property('saving'), }.property('saving'),
onShow: function() { onShow() {
this.setProperties({ this.setProperties({
'controllers.modal.modalClass': 'split-modal', 'controllers.modal.modalClass': 'split-modal',
saving: false, saving: false,
@ -31,10 +36,10 @@ export default ObjectController.extend(SelectedPostsCount, ModalFunctionality, P
}, },
actions: { actions: {
movePostsToNewTopic: function() { movePostsToNewTopic() {
this.set('saving', true); this.set('saving', true);
var postIds = this.get('selectedPosts').map(function(p) { return p.get('id'); }), const postIds = this.get('selectedPosts').map(function(p) { return p.get('id'); }),
replyPostIds = this.get('selectedReplies').map(function(p) { return p.get('id'); }), replyPostIds = this.get('selectedReplies').map(function(p) { return p.get('id'); }),
self = this, self = this,
categoryId = this.get('categoryId'), categoryId = this.get('categoryId'),
@ -46,24 +51,14 @@ export default ObjectController.extend(SelectedPostsCount, ModalFunctionality, P
if (!Ember.isNone(categoryId)) { saveOpts.category_id = categoryId; } if (!Ember.isNone(categoryId)) { saveOpts.category_id = categoryId; }
Discourse.Topic.movePosts(this.get('id'), saveOpts).then(function(result) { movePosts(this.get('model.id'), saveOpts).then(function(result) {
// Posts moved // Posts moved
self.send('closeModal'); self.send('closeModal');
self.get('topicController').send('toggleMultiSelect'); self.get('topicController').send('toggleMultiSelect');
Em.run.next(function() { Discourse.URL.routeTo(result.url); }); Ember.run.next(function() { Discourse.URL.routeTo(result.url); });
}).catch(function(xhr) { }).catch(function(xhr) {
self.flash(extractError(xhr, I18n.t('topic.split_topic.error')));
var error = I18n.t('topic.split_topic.error'); }).finally(function() {
if (xhr) {
var json = xhr.responseJSON;
if (json && json.errors) {
error = json.errors[0];
}
}
// Error moving posts
self.flash(error);
self.set('saving', false); self.set('saving', false);
}); });
return false; return false;

View File

@ -1,4 +1,4 @@
function extractError(error) { export function extractError(error, defaultMessage) {
if (error instanceof Error) { if (error instanceof Error) {
Ember.Logger.error(error.stack); Ember.Logger.error(error.stack);
} }
@ -42,7 +42,7 @@ function extractError(error) {
} }
} }
return parsedError || I18n.t('generic_error'); return parsedError || defaultMessage || I18n.t('generic_error');
} }
export function throwAjaxError(undoCallback) { export function throwAjaxError(undoCallback) {

View File

@ -1,3 +1,4 @@
import { flushMap } from 'discourse/models/store';
import RestModel from 'discourse/models/rest'; import RestModel from 'discourse/models/rest';
const Topic = RestModel.extend({ const Topic = RestModel.extend({
@ -462,28 +463,6 @@ Topic.reopenClass({
return Discourse.ajax(url + ".json", {data: data}); return Discourse.ajax(url + ".json", {data: data});
}, },
mergeTopic(topicId, destinationTopicId) {
const promise = Discourse.ajax("/t/" + topicId + "/merge-topic", {
type: 'POST',
data: {destination_topic_id: destinationTopicId}
}).then(function (result) {
if (result.success) return result;
promise.reject(new Error("error merging topic"));
});
return promise;
},
movePosts(topicId, opts) {
const promise = Discourse.ajax("/t/" + topicId + "/move-posts", {
type: 'POST',
data: opts
}).then(function (result) {
if (result.success) return result;
promise.reject(new Error("error moving posts topic"));
});
return promise;
},
changeOwners(topicId, opts) { changeOwners(topicId, opts) {
const promise = Discourse.ajax("/t/" + topicId + "/change-owner", { const promise = Discourse.ajax("/t/" + topicId + "/change-owner", {
type: 'POST', type: 'POST',
@ -523,4 +502,24 @@ Topic.reopenClass({
} }
}); });
function moveResult(result) {
if (result.success) {
// We should be hesitant to flush the map but moving ids is one rare case
flushMap();
return result;
}
throw "error moving posts topic";
}
export function movePosts(topicId, data) {
return Discourse.ajax("/t/" + topicId + "/move-posts", { type: 'POST', data }).then(moveResult);
}
export function mergeTopic(topicId, destinationTopicId) {
return Discourse.ajax("/t/" + topicId + "/merge-topic", {
type: 'POST',
data: {destination_topic_id: destinationTopicId}
}).then(moveResult);
}
export default Topic; export default Topic;

View File

@ -1,10 +1,4 @@
<div id='move-selected' class="modal-body"> <div id='move-selected' class="modal-body">
{{#if error}}
<div class="alert alert-error">
<button class="close" data-dismiss="alert">×</button>
</div>
{{/if}}
<p>{{{i18n 'topic.merge_topic.instructions' count=selectedPostsCount}}}</p> <p>{{{i18n 'topic.merge_topic.instructions' count=selectedPostsCount}}}</p>
<form> <form>
@ -13,5 +7,7 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button class='btn btn-primary' {{bind-attr disabled="buttonDisabled"}} {{action "movePostsToExistingTopic"}}><i class="fa fa-sign-out"></i>{{buttonTitle}}</button> {{#d-button class="btn-primary" disabled=buttonDisabled action="movePostsToExistingTopic"}}
{{fa-icon 'sign-out'}} {{buttonTitle}}
{{/d-button}}
</div> </div>

View File

@ -1,10 +1,4 @@
<div id='move-selected' class="modal-body"> <div id='move-selected' class="modal-body">
{{#if error}}
<div class="alert alert-error">
<button class="close" data-dismiss="alert">×</button>
</div>
{{/if}}
{{{i18n 'topic.split_topic.instructions' count=selectedPostsCount}}} {{{i18n 'topic.split_topic.instructions' count=selectedPostsCount}}}
<form> <form>
@ -18,5 +12,7 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button class='btn btn-primary' {{bind-attr disabled="buttonDisabled"}} {{action "movePostsToNewTopic"}}><i class='fa fa-sign-out'></i>{{buttonTitle}}</button> {{#d-button class="btn-primary" disabled=buttonDisabled action="movePostsToNewTopic"}}
{{fa-icon 'sign-out'}} {{buttonTitle}}
{{/d-button}}
</div> </div>

View File

@ -2,6 +2,6 @@ import SelectedPostsCount from 'discourse/mixins/selected-posts-count';
import ModalBodyView from "discourse/views/modal-body"; import ModalBodyView from "discourse/views/modal-body";
export default ModalBodyView.extend(SelectedPostsCount, { export default ModalBodyView.extend(SelectedPostsCount, {
templateName: 'modal/split_topic', templateName: 'modal/split-topic',
title: I18n.t('topic.split_topic.title') title: I18n.t('topic.split_topic.title')
}); });

View File

@ -28,6 +28,8 @@
//= require_tree ./discourse/adapters //= require_tree ./discourse/adapters
//= require ./discourse/models/rest //= require ./discourse/models/rest
//= require ./discourse/models/model //= require ./discourse/models/model
//= require ./discourse/models/result-set
//= require ./discourse/models/store
//= require ./discourse/models/post-action-type //= require ./discourse/models/post-action-type
//= require ./discourse/models/action-summary //= require ./discourse/models/action-summary
//= require ./discourse/models/post //= require ./discourse/models/post

View File

@ -123,11 +123,15 @@ class PostMover
end end
def create_moderator_post_in_original_topic def create_moderator_post_in_original_topic
move_type_str = PostMover.move_types[@move_type].to_s
original_topic.add_moderator_post( original_topic.add_moderator_post(
user, user,
I18n.t("move_posts.#{PostMover.move_types[@move_type]}_moderator_post", I18n.t("move_posts.#{move_type_str}_moderator_post",
count: post_ids.count, count: post_ids.count,
topic_link: "[#{destination_topic.title}](#{destination_topic.url})"), topic_link: "[#{destination_topic.title}](#{destination_topic.relative_url})"),
post_type: Post.types[:small_action],
action_code: "split_topic",
post_number: @first_post_number_moved post_number: @first_post_number_moved
) )
end end

View File

@ -120,6 +120,7 @@ en:
email: 'send this link in an email' email: 'send this link in an email'
action_codes: action_codes:
split_topic: "split this topic"
autoclosed: autoclosed:
enabled: 'closed this topic %{when}' enabled: 'closed this topic %{when}'
disabled: 'opened this topic %{when}' disabled: 'opened this topic %{when}'

View File

@ -1242,11 +1242,11 @@ en:
move_posts: move_posts:
new_topic_moderator_post: new_topic_moderator_post:
one: "I moved a post to a new topic: %{topic_link}" one: "A post was split to a new topic: %{topic_link}"
other: "I moved %{count} posts to a new topic: %{topic_link}" other: "%{count} posts were split to a new topic: %{topic_link}"
existing_topic_moderator_post: existing_topic_moderator_post:
one: "I moved a post to an existing topic: %{topic_link}" one: "A post was merged into an existing topic: %{topic_link}"
other: "I moved %{count} posts to an existing topic: %{topic_link}" other: "%{count} posts were merged into an existing topic: %{topic_link}"
change_owner: change_owner:
post_revision_text: "Ownership transferred from %{old_user} to %{new_user}" post_revision_text: "Ownership transferred from %{old_user} to %{new_user}"