mirror of
https://github.com/discourse/discourse.git
synced 2024-11-22 19:46:55 +08:00
FEATURE: move posts to new/existing PM (#6802)
This commit is contained in:
parent
b478984f60
commit
70fdc10365
|
@ -0,0 +1,64 @@
|
|||
import debounce from "discourse/lib/debounce";
|
||||
import { searchForTerm } from "discourse/lib/search";
|
||||
import { observes } from "ember-addons/ember-computed-decorators";
|
||||
|
||||
export default Ember.Component.extend({
|
||||
loading: null,
|
||||
noResults: null,
|
||||
messages: null,
|
||||
|
||||
@observes("messageTitle")
|
||||
messageTitleChanged() {
|
||||
this.setProperties({
|
||||
loading: true,
|
||||
noResults: true,
|
||||
selectedTopicId: null
|
||||
});
|
||||
this.search(this.get("messageTitle"));
|
||||
},
|
||||
|
||||
@observes("messages")
|
||||
messagesChanged() {
|
||||
const messages = this.get("messages");
|
||||
if (messages) {
|
||||
this.set("noResults", messages.length === 0);
|
||||
}
|
||||
this.set("loading", false);
|
||||
},
|
||||
|
||||
search: debounce(function(title) {
|
||||
const currentTopicId = this.get("currentTopicId");
|
||||
|
||||
if (Em.isEmpty(title)) {
|
||||
this.setProperties({ messages: null, loading: false });
|
||||
return;
|
||||
}
|
||||
|
||||
searchForTerm(title, {
|
||||
typeFilter: "private_messages",
|
||||
searchForId: true
|
||||
}).then(results => {
|
||||
if (results && results.posts && results.posts.length > 0) {
|
||||
this.set(
|
||||
"messages",
|
||||
results.posts
|
||||
.mapBy("topic")
|
||||
.filter(t => t.get("id") !== currentTopicId)
|
||||
);
|
||||
} else {
|
||||
this.setProperties({ messages: null, loading: false });
|
||||
}
|
||||
});
|
||||
}, 300),
|
||||
|
||||
actions: {
|
||||
chooseMessage(message) {
|
||||
const messageId = Em.get(message, "id");
|
||||
this.set("selectedTopicId", messageId);
|
||||
Ember.run.next(() =>
|
||||
$(`#choose-message-${messageId}`).prop("checked", "true")
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
|
@ -1,59 +0,0 @@
|
|||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||
import { movePosts, mergeTopic } from "discourse/models/topic";
|
||||
import DiscourseURL from "discourse/lib/url";
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
|
||||
export default Ember.Controller.extend(ModalFunctionality, {
|
||||
topicController: Ember.inject.controller("topic"),
|
||||
|
||||
saving: false,
|
||||
selectedTopicId: null,
|
||||
|
||||
selectedPostsCount: Ember.computed.alias(
|
||||
"topicController.selectedPostsCount"
|
||||
),
|
||||
|
||||
@computed("saving", "selectedTopicId")
|
||||
buttonDisabled(saving, selectedTopicId) {
|
||||
return saving || Ember.isEmpty(selectedTopicId);
|
||||
},
|
||||
|
||||
@computed("saving")
|
||||
buttonTitle(saving) {
|
||||
return saving ? I18n.t("saving") : I18n.t("topic.merge_topic.title");
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.set("modal.modalClass", "split-modal");
|
||||
},
|
||||
|
||||
actions: {
|
||||
movePostsToExistingTopic() {
|
||||
const topicId = this.get("model.id");
|
||||
|
||||
this.set("saving", true);
|
||||
|
||||
let promise = this.get("topicController.selectedAllPosts")
|
||||
? mergeTopic(topicId, this.get("selectedTopicId"))
|
||||
: movePosts(topicId, {
|
||||
destination_topic_id: this.get("selectedTopicId"),
|
||||
post_ids: this.get("topicController.selectedPostIds")
|
||||
});
|
||||
|
||||
promise
|
||||
.then(result => {
|
||||
this.send("closeModal");
|
||||
this.get("topicController").send("toggleMultiSelect");
|
||||
Ember.run.next(() => DiscourseURL.routeTo(result.url));
|
||||
})
|
||||
.catch(() => {
|
||||
this.flash(I18n.t("topic.merge_topic.error"));
|
||||
})
|
||||
.finally(() => {
|
||||
this.set("saving", false);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
|
@ -0,0 +1,155 @@
|
|||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||
import { movePosts, mergeTopic } from "discourse/models/topic";
|
||||
import DiscourseURL from "discourse/lib/url";
|
||||
import { default as computed } from "ember-addons/ember-computed-decorators";
|
||||
import { extractError } from "discourse/lib/ajax-error";
|
||||
|
||||
export default Ember.Controller.extend(ModalFunctionality, {
|
||||
topicName: null,
|
||||
saving: false,
|
||||
categoryId: null,
|
||||
tags: null,
|
||||
canAddTags: Ember.computed.alias("site.can_create_tag"),
|
||||
canTagMessages: Ember.computed.alias("site.can_tag_pms"),
|
||||
selectedTopicId: null,
|
||||
newTopic: Ember.computed.equal("selection", "new_topic"),
|
||||
existingTopic: Ember.computed.equal("selection", "existing_topic"),
|
||||
newMessage: Ember.computed.equal("selection", "new_message"),
|
||||
existingMessage: Ember.computed.equal("selection", "existing_message"),
|
||||
moveTypes: ["newTopic", "existingTopic", "newMessage", "existingMessage"],
|
||||
participants: null,
|
||||
|
||||
topicController: Ember.inject.controller("topic"),
|
||||
selectedPostsCount: Ember.computed.alias(
|
||||
"topicController.selectedPostsCount"
|
||||
),
|
||||
selectedAllPosts: Ember.computed.alias("topicController.selectedAllPosts"),
|
||||
selectedPosts: Ember.computed.alias("topicController.selectedPosts"),
|
||||
|
||||
@computed("saving", "selectedTopicId", "topicName")
|
||||
buttonDisabled(saving, selectedTopicId, topicName) {
|
||||
return (
|
||||
saving || (Ember.isEmpty(selectedTopicId) && Ember.isEmpty(topicName))
|
||||
);
|
||||
},
|
||||
|
||||
@computed(
|
||||
"saving",
|
||||
"newTopic",
|
||||
"existingTopic",
|
||||
"newMessage",
|
||||
"existingMessage"
|
||||
)
|
||||
buttonTitle(saving, newTopic, existingTopic, newMessage, existingMessage) {
|
||||
if (newTopic) {
|
||||
return I18n.t("topic.split_topic.title");
|
||||
} else if (existingTopic) {
|
||||
return I18n.t("topic.merge_topic.title");
|
||||
} else if (newMessage) {
|
||||
return I18n.t("topic.move_to_new_message.title");
|
||||
} else if (existingMessage) {
|
||||
return I18n.t("topic.move_to_existing_message.title");
|
||||
} else {
|
||||
return I18n.t("saving");
|
||||
}
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.setProperties({
|
||||
"modal.modalClass": "move-to-modal",
|
||||
saving: false,
|
||||
selection: "new_topic",
|
||||
categoryId: null,
|
||||
topicName: "",
|
||||
tags: null,
|
||||
participants: null
|
||||
});
|
||||
|
||||
const isPrivateMessage = this.get("model.isPrivateMessage");
|
||||
const canSplitTopic = this.get("canSplitTopic");
|
||||
if (isPrivateMessage) {
|
||||
this.set("selection", canSplitTopic ? "new_message" : "existing_message");
|
||||
} else if (!canSplitTopic) {
|
||||
this.set("selection", "existing_topic");
|
||||
}
|
||||
},
|
||||
|
||||
@computed("selectedAllPosts", "selectedPosts", "selectedPosts.[]")
|
||||
canSplitTopic(selectedAllPosts, selectedPosts) {
|
||||
return (
|
||||
!selectedAllPosts &&
|
||||
selectedPosts.length > 0 &&
|
||||
selectedPosts.sort((a, b) => a.post_number - b.post_number)[0]
|
||||
.post_type === this.site.get("post_types.regular")
|
||||
);
|
||||
},
|
||||
|
||||
actions: {
|
||||
performMove() {
|
||||
this.get("moveTypes").forEach(type => {
|
||||
if (this.get(type)) {
|
||||
this.send("movePostsTo", type);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
movePostsTo(type) {
|
||||
this.set("saving", true);
|
||||
const topicId = this.get("model.id");
|
||||
let mergeOptions, moveOptions;
|
||||
|
||||
if (type === "existingTopic") {
|
||||
mergeOptions = { destination_topic_id: this.get("selectedTopicId") };
|
||||
moveOptions = Object.assign(
|
||||
{ post_ids: this.get("topicController.selectedPostIds") },
|
||||
mergeOptions
|
||||
);
|
||||
} else if (type === "existingMessage") {
|
||||
mergeOptions = {
|
||||
destination_topic_id: this.get("selectedTopicId"),
|
||||
participants: this.get("participants"),
|
||||
archetype: "private_message"
|
||||
};
|
||||
moveOptions = Object.assign(
|
||||
{ post_ids: this.get("topicController.selectedPostIds") },
|
||||
mergeOptions
|
||||
);
|
||||
} else if (type === "newTopic") {
|
||||
mergeOptions = {};
|
||||
moveOptions = {
|
||||
title: this.get("topicName"),
|
||||
post_ids: this.get("topicController.selectedPostIds"),
|
||||
category_id: this.get("categoryId"),
|
||||
tags: this.get("tags")
|
||||
};
|
||||
} else {
|
||||
mergeOptions = {};
|
||||
moveOptions = {
|
||||
title: this.get("topicName"),
|
||||
post_ids: this.get("topicController.selectedPostIds"),
|
||||
tags: this.get("tags"),
|
||||
archetype: "private_message"
|
||||
};
|
||||
}
|
||||
|
||||
const promise = this.get("topicController.selectedAllPosts")
|
||||
? mergeTopic(topicId, mergeOptions)
|
||||
: movePosts(topicId, moveOptions);
|
||||
|
||||
promise
|
||||
.then(result => {
|
||||
this.send("closeModal");
|
||||
this.get("topicController").send("toggleMultiSelect");
|
||||
DiscourseURL.routeTo(result.url);
|
||||
})
|
||||
.catch(xhr => {
|
||||
this.flash(extractError(xhr, I18n.t("topic.move_to.error")));
|
||||
})
|
||||
.finally(() => {
|
||||
this.set("saving", false);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
|
@ -1,66 +0,0 @@
|
|||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||
import { extractError } from "discourse/lib/ajax-error";
|
||||
import { movePosts } from "discourse/models/topic";
|
||||
import DiscourseURL from "discourse/lib/url";
|
||||
import { default as computed } from "ember-addons/ember-computed-decorators";
|
||||
|
||||
export default Ember.Controller.extend(ModalFunctionality, {
|
||||
topicName: null,
|
||||
saving: false,
|
||||
categoryId: null,
|
||||
tags: null,
|
||||
canAddTags: Ember.computed.alias("site.can_create_tag"),
|
||||
|
||||
topicController: Ember.inject.controller("topic"),
|
||||
selectedPostsCount: Ember.computed.alias(
|
||||
"topicController.selectedPostsCount"
|
||||
),
|
||||
|
||||
@computed("saving", "topicName")
|
||||
buttonDisabled(saving, topicName) {
|
||||
return saving || Ember.isEmpty(topicName);
|
||||
},
|
||||
|
||||
@computed("saving")
|
||||
buttonTitle(saving) {
|
||||
return saving ? I18n.t("saving") : I18n.t("topic.split_topic.action");
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.setProperties({
|
||||
"modal.modalClass": "split-modal",
|
||||
saving: false,
|
||||
categoryId: null,
|
||||
topicName: "",
|
||||
tags: null
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
movePostsToNewTopic() {
|
||||
this.set("saving", true);
|
||||
|
||||
const options = {
|
||||
title: this.get("topicName"),
|
||||
post_ids: this.get("topicController.selectedPostIds"),
|
||||
category_id: this.get("categoryId"),
|
||||
tags: this.get("tags")
|
||||
};
|
||||
|
||||
movePosts(this.get("model.id"), options)
|
||||
.then(result => {
|
||||
this.send("closeModal");
|
||||
this.get("topicController").send("toggleMultiSelect");
|
||||
Ember.run.next(() => DiscourseURL.routeTo(result.url));
|
||||
})
|
||||
.catch(xhr => {
|
||||
this.flash(extractError(xhr, I18n.t("topic.split_topic.error")));
|
||||
})
|
||||
.finally(() => {
|
||||
this.set("saving", false);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
|
@ -1113,22 +1113,6 @@ export default Ember.Controller.extend(BufferedContent, {
|
|||
);
|
||||
},
|
||||
|
||||
@computed(
|
||||
"canMergeTopic",
|
||||
"selectedAllPosts",
|
||||
"selectedPosts",
|
||||
"selectedPosts.[]"
|
||||
)
|
||||
canSplitTopic(canMergeTopic, selectedAllPosts, selectedPosts) {
|
||||
return (
|
||||
canMergeTopic &&
|
||||
!selectedAllPosts &&
|
||||
selectedPosts.length > 0 &&
|
||||
selectedPosts.sort((a, b) => a.post_number - b.post_number)[0]
|
||||
.post_type === 1
|
||||
);
|
||||
},
|
||||
|
||||
@computed("model.details.can_move_posts", "selectedPostsCount")
|
||||
canMergeTopic(canMovePosts, selectedPostsCount) {
|
||||
return canMovePosts && selectedPostsCount > 0;
|
||||
|
|
|
@ -752,11 +752,10 @@ export function movePosts(topicId, data) {
|
|||
);
|
||||
}
|
||||
|
||||
export function mergeTopic(topicId, destinationTopicId) {
|
||||
return ajax("/t/" + topicId + "/merge-topic", {
|
||||
type: "POST",
|
||||
data: { destination_topic_id: destinationTopicId }
|
||||
}).then(moveResult);
|
||||
export function mergeTopic(topicId, data) {
|
||||
return ajax("/t/" + topicId + "/merge-topic", { type: "POST", data }).then(
|
||||
moveResult
|
||||
);
|
||||
}
|
||||
|
||||
export default Topic;
|
||||
|
|
|
@ -114,17 +114,13 @@ const TopicRoute = Discourse.Route.extend({
|
|||
this.controllerFor("raw_email").loadRawEmail(model.get("id"));
|
||||
},
|
||||
|
||||
mergeTopic() {
|
||||
showModal("merge-topic", {
|
||||
moveToTopic() {
|
||||
showModal("move-to-topic", {
|
||||
model: this.modelFor("topic"),
|
||||
title: "topic.merge_topic.title"
|
||||
title: "topic.move_to.title"
|
||||
});
|
||||
},
|
||||
|
||||
splitTopic() {
|
||||
showModal("split-topic", { model: this.modelFor("topic") });
|
||||
},
|
||||
|
||||
changeOwner() {
|
||||
showModal("change-owner", {
|
||||
model: this.modelFor("topic"),
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<label for='choose-message-title'>{{i18n 'choose_message.title.search'}}</label>
|
||||
|
||||
{{text-field value=messageTitle placeholderKey="choose_message.title.placeholder" id="choose-message-title"}}
|
||||
|
||||
{{#if loading}}
|
||||
<p>{{i18n 'loading'}}</p>
|
||||
{{else}}
|
||||
{{#if noResults}}
|
||||
<p>{{i18n 'choose_message.none_found'}}</p>
|
||||
{{else}}
|
||||
{{#each messages as |m|}}
|
||||
<div class='controls existing-message'>
|
||||
<label class='radio'>
|
||||
<input type='radio' id="choose-message-{{unbound m.id}}" name='choose_message_id' {{action "chooseMessage" m}}>
|
||||
<span class="message-title">
|
||||
{{m.title}}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{/if}}
|
|
@ -1,13 +0,0 @@
|
|||
{{#d-modal-body id='move-selected'}}
|
||||
<p>{{{i18n 'topic.merge_topic.instructions' count=selectedPostsCount}}}</p>
|
||||
|
||||
<form>
|
||||
{{choose-topic currentTopicId=model.id selectedTopicId=selectedTopicId}}
|
||||
</form>
|
||||
{{/d-modal-body}}
|
||||
|
||||
<div class="modal-footer">
|
||||
{{#d-button class="btn-primary" disabled=buttonDisabled action="movePostsToExistingTopic"}}
|
||||
{{d-icon 'sign-out'}} {{buttonTitle}}
|
||||
{{/d-button}}
|
||||
</div>
|
|
@ -0,0 +1,112 @@
|
|||
{{#d-modal-body id='move-selected'}}
|
||||
|
||||
{{#if model.isPrivateMessage}}
|
||||
<div class="radios">
|
||||
{{#if canSplitTopic}}
|
||||
<label class="radio-label" for="move-to-new-message">
|
||||
{{radio-button id='move-to-new-message' name="move-to-entity" value="new_message" selection=selection}}
|
||||
<b>{{i18n 'topic.move_to_new_message.radio_label'}}</b>
|
||||
</label>
|
||||
{{/if}}
|
||||
|
||||
<label class="radio-label" for="move-to-existing-message">
|
||||
{{radio-button id='move-to-existing-message' name="move-to-entity" value="existing_message" selection=selection}}
|
||||
<b>{{i18n 'topic.move_to_existing_message.radio_label'}}</b>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{{#if canSplitTopic}}
|
||||
{{#if newMessage}}
|
||||
<p>{{{i18n 'topic.move_to_new_message.instructions' count=selectedPostsCount}}}</p>
|
||||
<form>
|
||||
<label>{{i18n 'topic.move_to_new_message.message_title'}}</label>
|
||||
{{text-field value=topicName placeholderKey="composer.title_placeholder" elementId='split-topic-name'}}
|
||||
|
||||
{{#if canTagMessages}}
|
||||
<label>{{i18n 'tagging.tags'}}</label>
|
||||
{{tag-chooser tags=tags filterable=true}}
|
||||
{{/if}}
|
||||
</form>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{#if existingMessage}}
|
||||
<p>{{{i18n 'topic.move_to_existing_message.instructions' count=selectedPostsCount}}}</p>
|
||||
<form>
|
||||
{{choose-message currentTopicId=model.id selectedTopicId=selectedTopicId}}
|
||||
|
||||
<label>{{i18n 'topic.move_to_new_message.participants'}}</label>
|
||||
{{user-selector usernames=participants class="participant-selector"}}
|
||||
</form>
|
||||
{{/if}}
|
||||
|
||||
{{else}}
|
||||
|
||||
<div class="radios">
|
||||
{{#if canSplitTopic}}
|
||||
<label class="radio-label" for="move-to-new-topic">
|
||||
{{radio-button id='move-to-new-topic' name="move-to-entity" value="new_topic" selection=selection}}
|
||||
<b>{{i18n 'topic.split_topic.radio_label'}}</b>
|
||||
</label>
|
||||
{{/if}}
|
||||
|
||||
<label class="radio-label" for="move-to-existing-topic">
|
||||
{{radio-button id='move-to-existing-topic' name="move-to-entity" value="existing_topic" selection=selection}}
|
||||
<b>{{i18n 'topic.merge_topic.radio_label'}}</b>
|
||||
</label>
|
||||
|
||||
{{#if canSplitTopic}}
|
||||
<label class="radio-label" for="move-to-new-message">
|
||||
{{radio-button id='move-to-new-message' name="move-to-entity" value="new_message" selection=selection}}
|
||||
<b>{{i18n 'topic.move_to_new_message.radio_label'}}</b>
|
||||
</label>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if existingTopic}}
|
||||
<p>{{{i18n 'topic.merge_topic.instructions' count=selectedPostsCount}}}</p>
|
||||
<form>
|
||||
{{choose-topic currentTopicId=model.id selectedTopicId=selectedTopicId}}
|
||||
</form>
|
||||
{{/if}}
|
||||
|
||||
{{#if canSplitTopic}}
|
||||
{{#if newTopic}}
|
||||
<p>{{{i18n 'topic.split_topic.instructions' count=selectedPostsCount}}}</p>
|
||||
<form>
|
||||
<label>{{i18n 'topic.split_topic.topic_name'}}</label>
|
||||
{{text-field value=topicName placeholderKey="composer.title_placeholder" elementId='split-topic-name'}}
|
||||
|
||||
<label>{{i18n 'categories.category'}}</label>
|
||||
{{category-chooser value=categoryId class="small"}}
|
||||
{{#if canAddTags}}
|
||||
<label>{{i18n 'tagging.tags'}}</label>
|
||||
{{tag-chooser tags=tags filterable=true categoryId=categoryId}}
|
||||
{{/if}}
|
||||
</form>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{#if canSplitTopic}}
|
||||
{{#if newMessage}}
|
||||
<p>{{{i18n 'topic.move_to_new_message.instructions' count=selectedPostsCount}}}</p>
|
||||
<form>
|
||||
<label>{{i18n 'topic.move_to_new_message.message_title'}}</label>
|
||||
{{text-field value=topicName placeholderKey="composer.title_placeholder" elementId='split-topic-name'}}
|
||||
|
||||
{{#if canTagMessages}}
|
||||
<label>{{i18n 'tagging.tags'}}</label>
|
||||
{{tag-chooser tags=tags filterable=true}}
|
||||
{{/if}}
|
||||
</form>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{/d-modal-body}}
|
||||
|
||||
<div class="modal-footer">
|
||||
{{#d-button class="btn-primary" disabled=buttonDisabled action=(action "performMove")}}
|
||||
{{d-icon 'sign-out'}} {{buttonTitle}}
|
||||
{{/d-button}}
|
||||
</div>
|
|
@ -1,21 +0,0 @@
|
|||
{{#d-modal-body id="move-selected" title="topic.split_topic.title"}}
|
||||
{{{i18n 'topic.split_topic.instructions' count=selectedPostsCount}}}
|
||||
|
||||
<form>
|
||||
<label>{{i18n 'topic.split_topic.topic_name'}}</label>
|
||||
{{text-field value=topicName placeholderKey="composer.title_placeholder" elementId='split-topic-name'}}
|
||||
|
||||
<label>{{i18n 'categories.category'}}</label>
|
||||
{{category-chooser value=categoryId class="small"}}
|
||||
{{#if canAddTags}}
|
||||
<label>{{i18n 'tagging.tags'}}</label>
|
||||
{{tag-chooser tags=tags filterable=true categoryId=categoryId}}
|
||||
{{/if}}
|
||||
</form>
|
||||
{{/d-modal-body}}
|
||||
|
||||
<div class="modal-footer">
|
||||
{{#d-button class="btn-primary" disabled=buttonDisabled action="movePostsToNewTopic"}}
|
||||
{{d-icon 'sign-out'}} {{buttonTitle}}
|
||||
{{/d-button}}
|
||||
</div>
|
|
@ -12,12 +12,8 @@
|
|||
{{d-button action="deleteSelected" icon="trash-o" label="topic.multi_select.delete" class="btn-danger"}}
|
||||
{{/if}}
|
||||
|
||||
{{#if canSplitTopic}}
|
||||
{{d-button action="splitTopic" icon="sign-out" label="topic.split_topic.action"}}
|
||||
{{/if}}
|
||||
|
||||
{{#if canMergeTopic}}
|
||||
{{d-button action="mergeTopic" icon="sign-out" label="topic.merge_topic.action"}}
|
||||
{{d-button action=(route-action "moveToTopic") icon="sign-out" label="topic.move_to.action" class="move-to-topic"}}
|
||||
{{/if}}
|
||||
|
||||
{{#if canChangeOwner}}
|
||||
|
|
|
@ -113,19 +113,28 @@
|
|||
}
|
||||
}
|
||||
|
||||
.split-modal {
|
||||
.move-to-modal {
|
||||
.modal-body {
|
||||
position: relative;
|
||||
height: 350px;
|
||||
}
|
||||
|
||||
#move-selected {
|
||||
width: 475px;
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
input[type="radio"] {
|
||||
margin-right: 10px;
|
||||
.radios {
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
.radio-label {
|
||||
display: inline-block;
|
||||
padding-right: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
|
@ -142,9 +151,19 @@
|
|||
width: 95%;
|
||||
margin-top: 20px;
|
||||
#split-topic-name,
|
||||
#choose-topic-title {
|
||||
#choose-topic-title,
|
||||
#choose-message-title {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.participant-selector {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.ac-wrap {
|
||||
width: 100%;
|
||||
margin-bottom: 9px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -607,13 +607,26 @@ class TopicsController < ApplicationController
|
|||
end
|
||||
|
||||
def merge_topic
|
||||
params.require(:destination_topic_id)
|
||||
topic_id = params.require(:topic_id)
|
||||
destination_topic_id = params.require(:destination_topic_id)
|
||||
params.permit(:participants)
|
||||
params.permit(:archetype)
|
||||
|
||||
topic = Topic.find_by(id: params[:topic_id])
|
||||
raise Discourse::InvalidAccess if params[:archetype] == "private_message" && !guardian.is_staff?
|
||||
|
||||
topic = Topic.find_by(id: topic_id)
|
||||
guardian.ensure_can_move_posts!(topic)
|
||||
|
||||
dest_topic = topic.move_posts(current_user, topic.posts.pluck(:id), destination_topic_id: params[:destination_topic_id].to_i)
|
||||
render_topic_changes(dest_topic)
|
||||
args = {}
|
||||
args[:destination_topic_id] = destination_topic_id.to_i
|
||||
|
||||
if params[:archetype].present?
|
||||
args[:archetype] = params[:archetype]
|
||||
args[:participants] = params[:participants] if params[:participants].present? && params[:archetype] == "private_message"
|
||||
end
|
||||
|
||||
destination_topic = topic.move_posts(current_user, topic.posts.pluck(:id), args)
|
||||
render_topic_changes(destination_topic)
|
||||
end
|
||||
|
||||
def move_posts
|
||||
|
@ -621,6 +634,10 @@ class TopicsController < ApplicationController
|
|||
topic_id = params.require(:topic_id)
|
||||
params.permit(:category_id)
|
||||
params.permit(:tags)
|
||||
params.permit(:participants)
|
||||
params.permit(:archetype)
|
||||
|
||||
raise Discourse::InvalidAccess if params[:archetype] == "private_message" && !guardian.is_staff?
|
||||
|
||||
topic = Topic.with_deleted.find_by(id: topic_id)
|
||||
guardian.ensure_can_move_posts!(topic)
|
||||
|
@ -630,8 +647,8 @@ class TopicsController < ApplicationController
|
|||
return render_json_error("When moving posts to a new topic, the first post must be a regular post.")
|
||||
end
|
||||
|
||||
dest_topic = move_posts_to_destination(topic)
|
||||
render_topic_changes(dest_topic)
|
||||
destination_topic = move_posts_to_destination(topic)
|
||||
render_topic_changes(destination_topic)
|
||||
rescue ActiveRecord::RecordInvalid => ex
|
||||
render_json_error(ex)
|
||||
end
|
||||
|
@ -893,9 +910,15 @@ class TopicsController < ApplicationController
|
|||
args = {}
|
||||
args[:title] = params[:title] if params[:title].present?
|
||||
args[:destination_topic_id] = params[:destination_topic_id].to_i if params[:destination_topic_id].present?
|
||||
args[:category_id] = params[:category_id].to_i if params[:category_id].present?
|
||||
args[:tags] = params[:tags] if params[:tags].present?
|
||||
|
||||
if params[:archetype].present?
|
||||
args[:archetype] = params[:archetype]
|
||||
args[:participants] = params[:participants] if params[:participants].present? && params[:archetype] == "private_message"
|
||||
else
|
||||
args[:category_id] = params[:category_id].to_i if params[:category_id].present?
|
||||
end
|
||||
|
||||
topic.move_posts(current_user, post_ids_including_replies, args)
|
||||
end
|
||||
|
||||
|
|
|
@ -5,18 +5,24 @@ class PostMover
|
|||
@move_types ||= Enum.new(:new_topic, :existing_topic)
|
||||
end
|
||||
|
||||
def initialize(original_topic, user, post_ids)
|
||||
def initialize(original_topic, user, post_ids, move_to_pm: false)
|
||||
@original_topic = original_topic
|
||||
@user = user
|
||||
@post_ids = post_ids
|
||||
@move_to_pm = move_to_pm
|
||||
end
|
||||
|
||||
def to_topic(id)
|
||||
def to_topic(id, participants: nil)
|
||||
@move_type = PostMover.move_types[:existing_topic]
|
||||
|
||||
topic = Topic.find_by_id(id)
|
||||
raise Discourse::InvalidParameters unless topic.archetype == @original_topic.archetype
|
||||
|
||||
Topic.transaction do
|
||||
move_posts_to Topic.find_by_id(id)
|
||||
move_posts_to topic
|
||||
end
|
||||
add_allowed_users(participants) if participants.present? && @move_to_pm
|
||||
topic
|
||||
end
|
||||
|
||||
def to_new_topic(title, category_id = nil, tags = nil)
|
||||
|
@ -24,13 +30,15 @@ class PostMover
|
|||
|
||||
post = Post.find_by(id: post_ids.first)
|
||||
raise Discourse::InvalidParameters unless post
|
||||
archetype = @move_to_pm ? Archetype.private_message : Archetype.default
|
||||
|
||||
Topic.transaction do
|
||||
new_topic = Topic.create!(
|
||||
user: post.user,
|
||||
title: title,
|
||||
category_id: category_id,
|
||||
created_at: post.created_at
|
||||
created_at: post.created_at,
|
||||
archetype: archetype
|
||||
)
|
||||
DiscourseTagging.tag_topic_by_names(new_topic, Guardian.new(user), tags)
|
||||
move_posts_to new_topic
|
||||
|
@ -79,7 +87,11 @@ class PostMover
|
|||
|
||||
posts.each do |post|
|
||||
post.is_first_post? ? create_first_post(post) : move(post)
|
||||
if @move_to_pm
|
||||
destination_topic.topic_allowed_users.build(user_id: post.user_id) unless destination_topic.topic_allowed_users.where(user_id: post.user_id).exists?
|
||||
end
|
||||
end
|
||||
destination_topic.save! if @move_to_pm
|
||||
|
||||
PostReply.where("reply_id IN (:post_ids) OR post_id IN (:post_ids)", post_ids: post_ids).each do |post_reply|
|
||||
if post_reply.post && post_reply.reply && post_reply.reply.topic_id != post_reply.post.topic_id
|
||||
|
@ -189,6 +201,7 @@ class PostMover
|
|||
I18n.t(
|
||||
"move_posts.#{move_type_str}_moderator_post",
|
||||
count: posts.length,
|
||||
entity: @move_to_pm ? "message" : "topic",
|
||||
topic_link: posts.first.is_first_post? ?
|
||||
"[#{destination_topic.title}](#{destination_topic.relative_url})" :
|
||||
"[#{destination_topic.title}](#{posts.first.url})"
|
||||
|
@ -234,4 +247,14 @@ class PostMover
|
|||
notifications_reason_id: TopicUser.notification_reasons[:created_topic]
|
||||
)
|
||||
end
|
||||
|
||||
def add_allowed_users(usernames)
|
||||
return unless usernames.present?
|
||||
|
||||
names = usernames.split(',').flatten
|
||||
User.where(username: names).find_each do |user|
|
||||
destination_topic.topic_allowed_users.build(user_id: user.id) unless destination_topic.topic_allowed_users.where(user_id: user.id).exists?
|
||||
end
|
||||
destination_topic.save!
|
||||
end
|
||||
end
|
||||
|
|
|
@ -896,10 +896,10 @@ class Topic < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def move_posts(moved_by, post_ids, opts)
|
||||
post_mover = PostMover.new(self, moved_by, post_ids)
|
||||
post_mover = PostMover.new(self, moved_by, post_ids, move_to_pm: opts[:archetype].present? && opts[:archetype] == "private_message")
|
||||
|
||||
if opts[:destination_topic_id]
|
||||
topic = post_mover.to_topic(opts[:destination_topic_id])
|
||||
topic = post_mover.to_topic(opts[:destination_topic_id], participants: opts[:participants])
|
||||
|
||||
DiscourseEvent.trigger(:topic_merged,
|
||||
post_mover.original_topic,
|
||||
|
|
|
@ -347,9 +347,15 @@ en:
|
|||
choose_topic:
|
||||
none_found: "No topics found."
|
||||
title:
|
||||
search: "Search for a Topic by name, url or id:"
|
||||
search: "Search for a Topic by title, url or id:"
|
||||
placeholder: "type the topic title here"
|
||||
|
||||
choose_message:
|
||||
none_found: "No messages found."
|
||||
title:
|
||||
search: "Search for a Message by title:"
|
||||
placeholder: "type the message title here"
|
||||
|
||||
queue:
|
||||
topic: "Topic:"
|
||||
approve: 'Approve'
|
||||
|
@ -2004,10 +2010,16 @@ en:
|
|||
other: "{{count}} posts"
|
||||
cancel: "Remove filter"
|
||||
|
||||
move_to:
|
||||
title: "Move to"
|
||||
action: "move to"
|
||||
error: "There was an error moving posts."
|
||||
|
||||
split_topic:
|
||||
title: "Move to New Topic"
|
||||
action: "move to new topic"
|
||||
topic_name: "New Topic Name"
|
||||
topic_name: "New Topic Title"
|
||||
radio_label: "New Topic"
|
||||
error: "There was an error moving posts to the new topic."
|
||||
instructions:
|
||||
one: "You are about to create a new topic and populate it with the post you've selected."
|
||||
|
@ -2017,10 +2029,30 @@ en:
|
|||
title: "Move to Existing Topic"
|
||||
action: "move to existing topic"
|
||||
error: "There was an error moving posts into that topic."
|
||||
radio_label: "Existing Topic"
|
||||
instructions:
|
||||
one: "Please choose the topic you'd like to move that post to."
|
||||
other: "Please choose the topic you'd like to move those <b>{{count}}</b> posts to."
|
||||
|
||||
move_to_new_message:
|
||||
title: "Move to New Message"
|
||||
action: "move to new message"
|
||||
message_title: "New Message Title"
|
||||
radio_label: "New Message"
|
||||
participants: "Participants"
|
||||
instructions:
|
||||
one: "You are about to create a new message and populate it with the post you've selected."
|
||||
other: "You are about to create a new message and populate it with the <b>{{count}}</b> posts you've selected."
|
||||
|
||||
move_to_existing_message:
|
||||
title: "Move to Existing Message"
|
||||
action: "move to existing message"
|
||||
radio_label: "Existing Message"
|
||||
participants: "Participants"
|
||||
instructions:
|
||||
one: "Please choose the message you'd like to move that post to."
|
||||
other: "Please choose the message you'd like to move those <b>{{count}}</b> posts to."
|
||||
|
||||
merge_posts:
|
||||
title: "Merge Selected Posts"
|
||||
action: "merge selected posts"
|
||||
|
|
|
@ -1988,11 +1988,11 @@ en:
|
|||
|
||||
move_posts:
|
||||
new_topic_moderator_post:
|
||||
one: "A post was split to a new topic: %{topic_link}"
|
||||
other: "%{count} posts were split to a new topic: %{topic_link}"
|
||||
one: "A post was split to a new %{entity}: %{topic_link}"
|
||||
other: "%{count} posts were split to a new %{entity}: %{topic_link}"
|
||||
existing_topic_moderator_post:
|
||||
one: "A post was merged into an existing topic: %{topic_link}"
|
||||
other: "%{count} posts were merged into an existing topic: %{topic_link}"
|
||||
one: "A post was merged into an existing %{entity}: %{topic_link}"
|
||||
other: "%{count} posts were merged into an existing %{entity}: %{topic_link}"
|
||||
|
||||
change_owner:
|
||||
post_revision_text: "Ownership transferred"
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -241,6 +241,140 @@ RSpec.describe TopicsController do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'moving to a new message' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:trust_level_4) { Fabricate(:trust_level_4) }
|
||||
let(:moderator) { Fabricate(:moderator) }
|
||||
let!(:message) { Fabricate(:private_message_topic) }
|
||||
let!(:p1) { Fabricate(:post, user: user, post_number: 1, topic: message) }
|
||||
let!(:p2) { Fabricate(:post, user: user, post_number: 2, topic: message) }
|
||||
|
||||
it "raises an error without post_ids" do
|
||||
sign_in(moderator)
|
||||
post "/t/#{message.id}/move-posts.json", params: { title: 'blah', archetype: 'private_message' }
|
||||
expect(response.status).to eq(400)
|
||||
end
|
||||
|
||||
it "raises an error when the user doesn't have permission to move the posts" do
|
||||
sign_in(trust_level_4)
|
||||
|
||||
post "/t/#{message.id}/move-posts.json", params: {
|
||||
title: 'blah', post_ids: [p1.post_number, p2.post_number], archetype: 'private_message'
|
||||
}
|
||||
|
||||
expect(response.status).to eq(403)
|
||||
result = ::JSON.parse(response.body)
|
||||
expect(result['errors']).to be_present
|
||||
end
|
||||
|
||||
context 'success' do
|
||||
before { sign_in(Fabricate(:admin)) }
|
||||
|
||||
it "returns success" do
|
||||
SiteSetting.allow_staff_to_tag_pms = true
|
||||
|
||||
expect do
|
||||
post "/t/#{message.id}/move-posts.json", params: {
|
||||
title: 'Logan is a good movie',
|
||||
post_ids: [p2.id],
|
||||
archetype: 'private_message',
|
||||
tags: ["tag1", "tag2"]
|
||||
}
|
||||
end.to change { Topic.count }.by(1)
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
result = ::JSON.parse(response.body)
|
||||
|
||||
expect(result['success']).to eq(true)
|
||||
expect(result['url']).to eq(Topic.last.relative_url)
|
||||
expect(Tag.all.pluck(:name)).to contain_exactly("tag1", "tag2")
|
||||
end
|
||||
|
||||
describe 'when message has been deleted' do
|
||||
it 'should still be able to move posts' do
|
||||
PostDestroyer.new(Fabricate(:admin), message.first_post).destroy
|
||||
|
||||
expect(message.reload.deleted_at).to_not be_nil
|
||||
|
||||
expect do
|
||||
post "/t/#{message.id}/move-posts.json", params: {
|
||||
title: 'Logan is a good movie',
|
||||
post_ids: [p2.id],
|
||||
archetype: 'private_message'
|
||||
}
|
||||
end.to change { Topic.count }.by(1)
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(result['success']).to eq(true)
|
||||
expect(result['url']).to eq(Topic.last.relative_url)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'failure' do
|
||||
it "returns JSON with a false success" do
|
||||
sign_in(moderator)
|
||||
post "/t/#{message.id}/move-posts.json", params: {
|
||||
post_ids: [p2.id],
|
||||
archetype: 'private_message'
|
||||
}
|
||||
expect(response.status).to eq(200)
|
||||
result = ::JSON.parse(response.body)
|
||||
expect(result['success']).to eq(false)
|
||||
expect(result['url']).to be_blank
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'moving to an existing message' do
|
||||
let!(:user) { sign_in(Fabricate(:admin)) }
|
||||
let(:trust_level_4) { Fabricate(:trust_level_4) }
|
||||
let(:evil_trout) { Fabricate(:evil_trout) }
|
||||
let(:message) { Fabricate(:private_message_topic) }
|
||||
let(:p1) { Fabricate(:post, user: user, post_number: 1, topic: message) }
|
||||
let(:p2) { Fabricate(:post, user: evil_trout, post_number: 2, topic: message) }
|
||||
|
||||
let(:dest_message) do
|
||||
Fabricate(:private_message_topic, user: trust_level_4, topic_allowed_users: [
|
||||
Fabricate.build(:topic_allowed_user, user: evil_trout)
|
||||
])
|
||||
end
|
||||
|
||||
context 'success' do
|
||||
it "returns success" do
|
||||
user
|
||||
post "/t/#{message.id}/move-posts.json", params: {
|
||||
post_ids: [p2.id],
|
||||
destination_topic_id: dest_message.id,
|
||||
archetype: 'private_message'
|
||||
}
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
result = ::JSON.parse(response.body)
|
||||
expect(result['success']).to eq(true)
|
||||
expect(result['url']).to be_present
|
||||
end
|
||||
end
|
||||
|
||||
context 'failure' do
|
||||
it "returns JSON with a false success" do
|
||||
post "/t/#{message.id}/move-posts.json", params: {
|
||||
post_ids: [p2.id],
|
||||
archetype: 'private_message'
|
||||
}
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
result = ::JSON.parse(response.body)
|
||||
expect(result['success']).to eq(false)
|
||||
expect(result['url']).to be_blank
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#merge_topic' do
|
||||
|
@ -251,7 +385,7 @@ RSpec.describe TopicsController do
|
|||
expect(response.status).to eq(403)
|
||||
end
|
||||
|
||||
describe 'moving to a new topic' do
|
||||
describe 'merging into another topic' do
|
||||
let(:moderator) { Fabricate(:moderator) }
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:p1) { Fabricate(:post, user: user) }
|
||||
|
@ -285,6 +419,53 @@ RSpec.describe TopicsController do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'merging into another message' do
|
||||
let(:moderator) { Fabricate(:moderator) }
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:trust_level_4) { Fabricate(:trust_level_4) }
|
||||
let(:message) { Fabricate(:private_message_topic, user: user) }
|
||||
let!(:p1) { Fabricate(:post, topic: message, user: trust_level_4) }
|
||||
let!(:p2) { Fabricate(:post, topic: message, reply_to_post_number: p1.post_number, user: user) }
|
||||
|
||||
it "raises an error without destination_topic_id" do
|
||||
sign_in(moderator)
|
||||
post "/t/#{message.id}/merge-topic.json", params: {
|
||||
archetype: 'private_message'
|
||||
}
|
||||
expect(response.status).to eq(400)
|
||||
end
|
||||
|
||||
it "raises an error when the user doesn't have permission to merge" do
|
||||
sign_in(trust_level_4)
|
||||
post "/t/#{message.id}/merge-topic.json", params: {
|
||||
destination_topic_id: 345,
|
||||
archetype: 'private_message'
|
||||
}
|
||||
expect(response).to be_forbidden
|
||||
end
|
||||
|
||||
let(:dest_message) do
|
||||
Fabricate(:private_message_topic, user: trust_level_4, topic_allowed_users: [
|
||||
Fabricate.build(:topic_allowed_user, user: moderator)
|
||||
])
|
||||
end
|
||||
|
||||
context 'moves all the posts to the destination message' do
|
||||
it "returns success" do
|
||||
sign_in(moderator)
|
||||
post "/t/#{message.id}/merge-topic.json", params: {
|
||||
destination_topic_id: dest_message.id,
|
||||
archetype: 'private_message'
|
||||
}
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
result = ::JSON.parse(response.body)
|
||||
expect(result['success']).to eq(true)
|
||||
expect(result['url']).to be_present
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#change_post_owners' do
|
||||
|
|
121
test/javascripts/acceptance/topic-move-posts-test.js.es6
Normal file
121
test/javascripts/acceptance/topic-move-posts-test.js.es6
Normal file
|
@ -0,0 +1,121 @@
|
|||
import { acceptance } from "helpers/qunit-helpers";
|
||||
acceptance("Topic move posts", { loggedIn: true });
|
||||
|
||||
QUnit.test("default", async assert => {
|
||||
await visit("/t/internationalization-localization");
|
||||
await click(".toggle-admin-menu");
|
||||
await click(".topic-admin-multi-select .btn");
|
||||
await click("#post_11 .select-below");
|
||||
|
||||
assert.equal(
|
||||
find(".selected-posts .move-to-topic")
|
||||
.text()
|
||||
.trim(),
|
||||
I18n.t("topic.move_to.action"),
|
||||
"it should show the move to button"
|
||||
);
|
||||
|
||||
await click(".selected-posts .move-to-topic");
|
||||
|
||||
assert.ok(
|
||||
find(".move-to-modal .title")
|
||||
.html()
|
||||
.includes(I18n.t("topic.move_to.title")),
|
||||
"it opens move to modal"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
find(".move-to-modal .radios")
|
||||
.html()
|
||||
.includes(I18n.t("topic.split_topic.radio_label")),
|
||||
"it shows an option to move to new topic"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
find(".move-to-modal .radios")
|
||||
.html()
|
||||
.includes(I18n.t("topic.merge_topic.radio_label")),
|
||||
"it shows an option to move to existing topic"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
find(".move-to-modal .radios")
|
||||
.html()
|
||||
.includes(I18n.t("topic.move_to_new_message.radio_label")),
|
||||
"it shows an option to move to new message"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("moving all posts", async assert => {
|
||||
await visit("/t/internationalization-localization");
|
||||
await click(".toggle-admin-menu");
|
||||
await click(".topic-admin-multi-select .btn");
|
||||
await click(".select-all");
|
||||
await click(".selected-posts .move-to-topic");
|
||||
|
||||
assert.ok(
|
||||
find(".move-to-modal .title")
|
||||
.html()
|
||||
.includes(I18n.t("topic.move_to.title")),
|
||||
"it opens move to modal"
|
||||
);
|
||||
|
||||
assert.not(
|
||||
find(".move-to-modal .radios")
|
||||
.html()
|
||||
.includes(I18n.t("topic.split_topic.radio_label")),
|
||||
"it does not show an option to move to new topic"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
find(".move-to-modal .radios")
|
||||
.html()
|
||||
.includes(I18n.t("topic.merge_topic.radio_label")),
|
||||
"it shows an option to move to existing topic"
|
||||
);
|
||||
|
||||
assert.not(
|
||||
find(".move-to-modal .radios")
|
||||
.html()
|
||||
.includes(I18n.t("topic.move_to_new_message.radio_label")),
|
||||
"it does not show an option to move to new message"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("moving posts from personal message", async assert => {
|
||||
await visit("/t/pm-for-testing/12");
|
||||
await click(".toggle-admin-menu");
|
||||
await click(".topic-admin-multi-select .btn");
|
||||
await click("#post_1 .select-post");
|
||||
|
||||
assert.equal(
|
||||
find(".selected-posts .move-to-topic")
|
||||
.text()
|
||||
.trim(),
|
||||
I18n.t("topic.move_to.action"),
|
||||
"it should show the move to button"
|
||||
);
|
||||
|
||||
await click(".selected-posts .move-to-topic");
|
||||
|
||||
assert.ok(
|
||||
find(".move-to-modal .title")
|
||||
.html()
|
||||
.includes(I18n.t("topic.move_to.title")),
|
||||
"it opens move to modal"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
find(".move-to-modal .radios")
|
||||
.html()
|
||||
.includes(I18n.t("topic.move_to_new_message.radio_label")),
|
||||
"it shows an option to move to new message"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
find(".move-to-modal .radios")
|
||||
.html()
|
||||
.includes(I18n.t("topic.move_to_existing_message.radio_label")),
|
||||
"it shows an option to move to existing message"
|
||||
);
|
||||
});
|
|
@ -281,10 +281,6 @@ QUnit.test("Can split/merge topic", function(assert) {
|
|||
const controller = this.subject({ model });
|
||||
const selectedPostIds = controller.get("selectedPostIds");
|
||||
|
||||
assert.not(
|
||||
controller.get("canSplitTopic"),
|
||||
"can't split topic when no posts are selected"
|
||||
);
|
||||
assert.not(
|
||||
controller.get("canMergeTopic"),
|
||||
"can't merge topic when no posts are selected"
|
||||
|
@ -292,10 +288,6 @@ QUnit.test("Can split/merge topic", function(assert) {
|
|||
|
||||
selectedPostIds.pushObject(1);
|
||||
|
||||
assert.not(
|
||||
controller.get("canSplitTopic"),
|
||||
"can't split topic when can't move posts"
|
||||
);
|
||||
assert.not(
|
||||
controller.get("canMergeTopic"),
|
||||
"can't merge topic when can't move posts"
|
||||
|
@ -303,16 +295,11 @@ QUnit.test("Can split/merge topic", function(assert) {
|
|||
|
||||
model.set("details.can_move_posts", true);
|
||||
|
||||
assert.ok(controller.get("canSplitTopic"), "can split topic");
|
||||
assert.ok(controller.get("canMergeTopic"), "can merge topic");
|
||||
|
||||
selectedPostIds.removeObject(1);
|
||||
selectedPostIds.pushObject(2);
|
||||
|
||||
assert.not(
|
||||
controller.get("canSplitTopic"),
|
||||
"can't split topic when 1st post is not a regular post"
|
||||
);
|
||||
assert.ok(
|
||||
controller.get("canMergeTopic"),
|
||||
"can merge topic when 1st post is not a regular post"
|
||||
|
@ -320,10 +307,6 @@ QUnit.test("Can split/merge topic", function(assert) {
|
|||
|
||||
selectedPostIds.pushObject(3);
|
||||
|
||||
assert.not(
|
||||
controller.get("canSplitTopic"),
|
||||
"can't split topic when all posts are selected"
|
||||
);
|
||||
assert.ok(
|
||||
controller.get("canMergeTopic"),
|
||||
"can merge topic when all posts are selected"
|
||||
|
|
Loading…
Reference in New Issue
Block a user