diff --git a/assets/javascripts/discourse-assign/connectors/topic-footer-main-buttons-before-create/assign-button.js.es6 b/assets/javascripts/discourse-assign/connectors/topic-footer-main-buttons-before-create/assign-button.js.es6
index 04fa018..ea78d64 100644
--- a/assets/javascripts/discourse-assign/connectors/topic-footer-main-buttons-before-create/assign-button.js.es6
+++ b/assets/javascripts/discourse-assign/connectors/topic-footer-main-buttons-before-create/assign-button.js.es6
@@ -1,5 +1,4 @@
-import showModal from "discourse/lib/show-modal";
-import { ajax } from "discourse/lib/ajax";
+import { getOwner } from "discourse-common/lib/get-owner";
export default {
shouldRender(args, component) {
@@ -11,22 +10,18 @@ export default {
);
},
+ setupComponent(args, component) {
+ const taskActions = getOwner(this).lookup("service:task-actions");
+ component.set("taskActions", taskActions);
+ },
+
actions: {
unassign() {
this.set("topic.assigned_to_user", null);
-
- return ajax("/assign/unassign", {
- type: "PUT",
- data: { topic_id: this.get("topic.id") }
- });
+ this.get("taskActions").unassign(this.get("topic.id"));
},
assign() {
- showModal("assign-user", {
- model: {
- topic: this.topic,
- username: this.topic.get("assigned_to_user.username")
- }
- });
+ this.get("taskActions").assign(this.topic);
}
}
};
diff --git a/assets/javascripts/discourse-assign/controllers/assign-user.js.es6 b/assets/javascripts/discourse-assign/controllers/assign-user.js.es6
index 1661570..da6bcae 100644
--- a/assets/javascripts/discourse-assign/controllers/assign-user.js.es6
+++ b/assets/javascripts/discourse-assign/controllers/assign-user.js.es6
@@ -44,7 +44,9 @@ export default Ember.Controller.extend({
}
})
.then(() => {
- // done
+ if (this.get("model.onSuccess")) {
+ this.get("model.onSuccess")();
+ }
})
.catch(popupAjaxError);
}
diff --git a/assets/javascripts/discourse-assign/controllers/user-activity-assigned.js.es6 b/assets/javascripts/discourse-assign/controllers/user-activity-assigned.js.es6
index cd1c8aa..b87b23d 100644
--- a/assets/javascripts/discourse-assign/controllers/user-activity-assigned.js.es6
+++ b/assets/javascripts/discourse-assign/controllers/user-activity-assigned.js.es6
@@ -1,8 +1,10 @@
import { ajax } from "discourse/lib/ajax";
import computed from "ember-addons/ember-computed-decorators";
+import UserTopicsList from "discourse/controllers/user-topics-list";
-export default Ember.Controller.extend({
+export default UserTopicsList.extend({
user: Ember.inject.controller(),
+ taskActions: Ember.inject.service(),
@computed("model.topics")
canUnassignAll(topics) {
@@ -21,10 +23,19 @@ export default Ember.Controller.extend({
ajax("/assign/unassign-all", {
type: "PUT",
data: { user_id: user.get("id") }
- }).then(() => this.send("unassignedAll"));
+ }).then(() => this.send("changeAssigned"));
}
}
);
+ },
+ unassign(topic) {
+ this.get("taskActions")
+ .unassign(topic.get("id"))
+ .then(() => this.send("changeAssigned"));
+ },
+ reassign(topic) {
+ const controller = this.get("taskActions").assign(topic);
+ controller.set("model.onSuccess", () => this.send("changeAssigned"));
}
}
});
diff --git a/assets/javascripts/discourse-assign/initializers/extend-for-assigns.js.es6 b/assets/javascripts/discourse-assign/initializers/extend-for-assigns.js.es6
index 1fddd87..7ad9b70 100644
--- a/assets/javascripts/discourse-assign/initializers/extend-for-assigns.js.es6
+++ b/assets/javascripts/discourse-assign/initializers/extend-for-assigns.js.es6
@@ -8,6 +8,9 @@ import { iconNode } from "discourse-common/lib/icon-library";
import { h } from "virtual-dom";
import { iconHTML } from "discourse-common/lib/icon-library";
+// TODO: This has to be removed when 2.3 becomes the new stable version.
+import { ListItemDefaults } from "discourse/components/topic-list-item";
+
const ACTION_ID = "assign";
function modifySelectKit(api) {
@@ -138,9 +141,18 @@ function initialize(api) {
const assignedTo = topic.get("assigned_to_user.username");
if (assignedTo) {
const assignedPath = topic.get("assignedToUserPath");
- return `${iconHTML(
+ let assignLabels = `${iconHTML(
"user-plus"
)}${assignedTo}`;
+
+ if (
+ ListItemDefaults === undefined &&
+ topic.get("archetype") === "private_message"
+ ) {
+ assignLabels += `
${iconHTML("envelope")} Message
`;
+ }
+
+ return assignLabels;
}
});
diff --git a/assets/javascripts/discourse-assign/routes/user-activity-assigned.js.es6 b/assets/javascripts/discourse-assign/routes/user-activity-assigned.js.es6
index ef89462..72f43dd 100644
--- a/assets/javascripts/discourse-assign/routes/user-activity-assigned.js.es6
+++ b/assets/javascripts/discourse-assign/routes/user-activity-assigned.js.es6
@@ -1,4 +1,5 @@
import UserTopicListRoute from "discourse/routes/user-topic-list";
+import { ListItemDefaults } from "discourse/components/topic-list-item";
export default UserTopicListRoute.extend({
userActionType: 16,
@@ -6,9 +7,10 @@ export default UserTopicListRoute.extend({
model() {
return this.store.findFiltered("topicList", {
- filter: "latest",
+ filter: `topics/messages-assigned/${this.modelFor("user").get(
+ "username_lower"
+ )}`,
params: {
- assigned: this.modelFor("user").get("username_lower"),
// core is a bit odd here and is not sending an array, should be fixed
exclude_category_ids: [-1]
}
@@ -16,8 +18,12 @@ export default UserTopicListRoute.extend({
},
renderTemplate() {
+ // TODO: This has to be removed when 2.3 becomes the new stable version.
+ const template = ListItemDefaults
+ ? "user-assigned-topics"
+ : "user-topics-list";
this.render("user-activity-assigned");
- this.render("user-topics-list", { into: "user-activity-assigned" });
+ this.render(template, { into: "user-activity-assigned" });
},
setupController(controller, model) {
@@ -26,7 +32,7 @@ export default UserTopicListRoute.extend({
},
actions: {
- unassignedAll() {
+ changeAssigned() {
this.refresh();
}
}
diff --git a/assets/javascripts/discourse/components/assign-actions-dropdown.js.es6 b/assets/javascripts/discourse/components/assign-actions-dropdown.js.es6
new file mode 100644
index 0000000..88ed3e4
--- /dev/null
+++ b/assets/javascripts/discourse/components/assign-actions-dropdown.js.es6
@@ -0,0 +1,39 @@
+import DropdownSelectBoxComponent from "select-kit/components/dropdown-select-box";
+
+export default DropdownSelectBoxComponent.extend({
+ classNames: ["assign-actions-dropdown"],
+ headerIcon: null,
+ title: "...",
+ allowInitialValueMutation: false,
+ showFullTitle: true,
+
+ computeContent() {
+ return [
+ {
+ id: "unassign",
+ icon: "user-times",
+ name: I18n.t("discourse_assign.unassign.title"),
+ description: I18n.t("discourse_assign.unassign.help")
+ },
+ {
+ id: "reassign",
+ icon: "users",
+ name: I18n.t("discourse_assign.reassign.title"),
+ description: I18n.t("discourse_assign.reassign.help")
+ }
+ ];
+ },
+
+ actions: {
+ onSelect(id) {
+ switch (id) {
+ case "unassign":
+ this.unassign(this.get("topic"), this.get("user"));
+ break;
+ case "reassign":
+ this.reassign(this.get("topic"), this.get("user"));
+ break;
+ }
+ }
+ }
+});
diff --git a/assets/javascripts/discourse/components/assigned-topic-list-item.js.es6 b/assets/javascripts/discourse/components/assigned-topic-list-item.js.es6
new file mode 100644
index 0000000..a9eaa15
--- /dev/null
+++ b/assets/javascripts/discourse/components/assigned-topic-list-item.js.es6
@@ -0,0 +1,11 @@
+import computed from "ember-addons/ember-computed-decorators";
+import { ListItemDefaults } from "discourse/components/topic-list-item";
+
+const privateMessageHelper = {
+ @computed("topic.archetype")
+ isPrivateMessage(archetype) {
+ return archetype === "private_message";
+ }
+};
+
+export default Ember.Component.extend(ListItemDefaults, privateMessageHelper);
diff --git a/assets/javascripts/discourse/components/assigned-topic-list.js.es6 b/assets/javascripts/discourse/components/assigned-topic-list.js.es6
new file mode 100644
index 0000000..0bbb097
--- /dev/null
+++ b/assets/javascripts/discourse/components/assigned-topic-list.js.es6
@@ -0,0 +1,3 @@
+import TopicList from "discourse/components/topic-list";
+
+export default TopicList;
diff --git a/assets/javascripts/discourse/components/basic-assigned-topic-list.js.es6 b/assets/javascripts/discourse/components/basic-assigned-topic-list.js.es6
new file mode 100644
index 0000000..7a21ef3
--- /dev/null
+++ b/assets/javascripts/discourse/components/basic-assigned-topic-list.js.es6
@@ -0,0 +1,3 @@
+import BasicTopicList from "discourse/components/basic-topic-list";
+
+export default BasicTopicList;
diff --git a/assets/javascripts/discourse/services/task-actions.js.es6 b/assets/javascripts/discourse/services/task-actions.js.es6
new file mode 100644
index 0000000..41bf387
--- /dev/null
+++ b/assets/javascripts/discourse/services/task-actions.js.es6
@@ -0,0 +1,20 @@
+import { ajax } from "discourse/lib/ajax";
+import showModal from "discourse/lib/show-modal";
+
+export default Ember.Service.extend({
+ unassign(topicId) {
+ return ajax("/assign/unassign", {
+ type: "PUT",
+ data: { topic_id: topicId }
+ });
+ },
+
+ assign(topic) {
+ return showModal("assign-user", {
+ model: {
+ topic: topic,
+ username: topic.get("assigned_to_user.username")
+ }
+ });
+ }
+});
diff --git a/assets/javascripts/discourse/templates/components/assigned-topic-list-item.hbs b/assets/javascripts/discourse/templates/components/assigned-topic-list-item.hbs
new file mode 100644
index 0000000..97dfd4f
--- /dev/null
+++ b/assets/javascripts/discourse/templates/components/assigned-topic-list-item.hbs
@@ -0,0 +1,50 @@
+{{!--
+ The `~` syntax strip spaces between the elements, making it produce
+ `Some text`,
+ with no space between them.
+ This causes the topic-post-badge to be considered the same word as "text"
+ at the end of the link, preventing it from line wrapping onto its own line.
+--}}
+
+
+ {{~raw "topic-status" topic=topic}}
+ {{~#if isPrivateMessage}}
+ {{~d-icon "envelope" class="private-message-icon"}}
+ {{~/if}}
+ {{~topic-link topic class="raw-link raw-topic-link"}}
+ {{~#if topic.featured_link}}
+ {{~topic-featured-link topic}}
+ {{~/if}}
+ {{~#if showTopicPostBadges}}
+ {{~raw "topic-post-badges" unread=topic.unread newPosts=topic.displayNewPosts unseen=topic.unseen url=topic.lastUnreadUrl newDotText=newDotText}}
+ {{~/if}}
+
+
+ {{#unless hideCategory}}
+ {{#unless topic.isPinnedUncategorized}}
+ {{category-link topic.category}}
+ {{/unless}}
+ {{/unless}}
+ {{discourse-tags topic mode="list" tagsForUser=tagsForUser}}
+ {{raw "list/action-list" topic=topic postNumbers=topic.liked_post_numbers className="likes" icon="heart"}}
+
+ {{#if expandPinned}}
+ {{raw "list/topic-excerpt" topic=topic}}
+ {{/if}}
+ |
+
+{{#if showPosters}}
+ {{raw "list/posters-column" posters=topic.featuredUsers}}
+{{/if}}
+
+{{raw "list/posts-count-column" topic=topic}}
+
+{{number topic.views numberKey="views_long"}} |
+{{raw "list/activity-column" topic=topic class="num" tagName="td"}}
+
+
+ {{assign-actions-dropdown topic=topic
+ user=username
+ unassign=unassign
+ reassign=reassign}}
+ |
diff --git a/assets/javascripts/discourse/templates/components/assigned-topic-list.hbs b/assets/javascripts/discourse/templates/components/assigned-topic-list.hbs
new file mode 100644
index 0000000..0ab572b
--- /dev/null
+++ b/assets/javascripts/discourse/templates/components/assigned-topic-list.hbs
@@ -0,0 +1,34 @@
+{{#unless skipHeader}}
+
+ {{raw "topic-list-header"
+ toggleInTitle=toggleInTitle
+ hideCategory=hideCategory
+ showPosters=showPosters
+ showLikes=showLikes
+ showOpLikes=showOpLikes
+ order=order
+ ascending=ascending
+ sortable=sortable
+ listTitle=listTitle
+ bulkSelectEnabled=bulkSelectEnabled}}
+
+{{/unless}}
+
+
+ {{#each filteredTopics as |topic|}}
+ {{assigned-topic-list-item topic=topic
+ showTopicPostBadges=showTopicPostBadges
+ hideCategory=hideCategory
+ showPosters=showPosters
+ showLikes=showLikes
+ showOpLikes=showOpLikes
+ expandGloballyPinned=expandGloballyPinned
+ expandAllPinned=expandAllPinned
+ lastVisitedTopic=lastVisitedTopic
+ selected=selected
+ tagsForUser=tagsForUser
+ unassign=unassign
+ reassign=reassign}}
+ {{raw "list/visited-line" lastVisitedTopic=lastVisitedTopic topic=topic}}
+ {{/each}}
+
diff --git a/assets/javascripts/discourse/templates/components/basic-assigned-topic-list.hbs b/assets/javascripts/discourse/templates/components/basic-assigned-topic-list.hbs
new file mode 100644
index 0000000..d1a881f
--- /dev/null
+++ b/assets/javascripts/discourse/templates/components/basic-assigned-topic-list.hbs
@@ -0,0 +1,29 @@
+{{#conditional-loading-spinner condition=loading}}
+ {{#if hasIncoming}}
+
+ {{/if}}
+
+ {{#if topics}}
+ {{assigned-topic-list showPosters=showPosters
+ hideCategory=hideCategory
+ topics=topics
+ expandExcerpts=expandExcerpts
+ selected=selected
+ skipHeader=skipHeader
+ tagsForUser=tagsForUser
+ unassign=unassign
+ reassign=reassign}}
+ {{else}}
+ {{#unless loadingMore}}
+
+ {{i18n 'choose_topic.none_found'}}
+
+ {{/unless}}
+ {{/if}}
+{{/conditional-loading-spinner}}
\ No newline at end of file
diff --git a/assets/javascripts/discourse/templates/user-activity-assigned.hbs b/assets/javascripts/discourse/templates/user-activity-assigned.hbs
index 5f6be7d..8728c39 100644
--- a/assets/javascripts/discourse/templates/user-activity-assigned.hbs
+++ b/assets/javascripts/discourse/templates/user-activity-assigned.hbs
@@ -1,11 +1,4 @@
- {{#if model.topic_list.assigned_messages_count}}
- {{#link-to 'userPrivateMessages.assigned' user.model class="btn btn-default assign-messages-assigned"}}
- {{d-icon "envelope" class="glyph"}}
- {{i18n 'user.messages.assigned_title' count=model.topic_list.assigned_messages_count}}
- {{/link-to}}
- {{/if}}
-
{{#if canUnassignAll}}
{{d-button
action=(action "unassignAll")
diff --git a/assets/javascripts/discourse/templates/user-assigned-topics.hbs b/assets/javascripts/discourse/templates/user-assigned-topics.hbs
new file mode 100644
index 0000000..fc9b17d
--- /dev/null
+++ b/assets/javascripts/discourse/templates/user-assigned-topics.hbs
@@ -0,0 +1,17 @@
+{{#load-more class="paginated-topics-list" selector=".paginated-topics-list .topic-list tr" action=(action "loadMore")}}
+ {{basic-assigned-topic-list topicList=model
+ hideCategory=hideCategory
+ showPosters=showPosters
+ bulkSelectEnabled=bulkSelectEnabled
+ selected=selected
+ hasIncoming=hasIncoming
+ incomingCount=incomingCount
+ showInserted=(action "showInserted")
+ tagsForUser=tagsForUser
+ unassign=(action 'unassign')
+ reassign=(action 'reassign')}}
+
+ {{conditional-loading-spinner condition=model.loadingMore}}
+{{/load-more}}
+
+
diff --git a/assets/stylesheets/assigns.scss b/assets/stylesheets/assigns.scss
index 9b756fc..262194d 100644
--- a/assets/stylesheets/assigns.scss
+++ b/assets/stylesheets/assigns.scss
@@ -74,3 +74,7 @@
cursor: pointer;
}
}
+
+.private-message-icon {
+ margin-right: 2px;
+}
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 633c349..e7a6e11 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -18,6 +18,9 @@ en:
assign:
title: "Assign"
help: "Assign Topic to User"
+ reassign:
+ title: "Re-assign"
+ help: "Re-assign Topic to a different user"
assign_modal:
title: "Assign Topic"
description: "Enter the username of the person you'd like to assign this topic"
diff --git a/plugin.rb b/plugin.rb
index fbcf71a..238b2e5 100644
--- a/plugin.rb
+++ b/plugin.rb
@@ -18,6 +18,7 @@ load File.expand_path('../lib/discourse_assign/helpers.rb', __FILE__)
Discourse::Application.routes.append do
mount ::DiscourseAssign::Engine, at: "/assign"
get "topics/private-messages-assigned/:username" => "list#private_messages_assigned", as: "topics_private_messages_assigned", constraints: { username: /[\w.\-]+?/ }
+ get "topics/messages-assigned/:username" => "list#messages_assigned", as: "topics_messages_assigned", constraints: { username: /[\w.\-]+?/ }
end
after_initialize do
@@ -139,6 +140,17 @@ after_initialize do
require_dependency 'list_controller'
class ::ListController
generate_message_route(:private_messages_assigned)
+ generate_message_route(:messages_assigned)
+ end
+
+ add_to_class(:topic_query, :list_messages_assigned) do |user|
+ list = joined_topic_user.where("
+ topics.id IN (
+ SELECT topic_id FROM topic_custom_fields
+ WHERE name = 'assigned_to_id'
+ AND value = ?)
+ ", user.id.to_s)
+ create_list(:assigned, {}, list)
end
add_to_class(:topic_query, :list_private_messages_assigned) do |user|
diff --git a/spec/components/topic_query_spec.rb b/spec/components/topic_query_spec.rb
index 8d1a163..f5f5402 100644
--- a/spec/components/topic_query_spec.rb
+++ b/spec/components/topic_query_spec.rb
@@ -1,10 +1,36 @@
require 'rails_helper'
describe TopicQuery do
- describe '#list_private_messages_assigned' do
- let(:user) { Fabricate(:user) }
- let(:user2) { Fabricate(:user) }
+ before do
+ SiteSetting.assign_enabled = true
+ end
+ let(:user) { Fabricate(:user) }
+ let(:user2) { Fabricate(:user) }
+
+ describe '#list_messages_assigned' do
+ before do
+ @private_message = Fabricate(:private_message_topic, user: user)
+ @topic = Fabricate(:topic, user: user)
+
+ assign_to(@private_message, user)
+ assign_to(@topic, user)
+ end
+
+ it 'Includes topics and PMs assigned to user' do
+ assigned_messages = TopicQuery.new(user).list_messages_assigned(user).topics
+
+ expect(assigned_messages).to contain_exactly(@private_message, @topic)
+ end
+
+ it 'Excludes topics and PMs not assigned to user' do
+ assigned_messages = TopicQuery.new(user2).list_messages_assigned(user2).topics
+
+ expect(assigned_messages).to be_empty
+ end
+ end
+
+ describe '#list_private_messages_assigned' do
let(:user_topic) do
topic = Fabricate(:private_message_topic,
topic_allowed_users: [
@@ -24,10 +50,7 @@ describe TopicQuery do
Fabricate.build(:topic_allowed_user, user: user2)
],
)
-
- topic.posts << Fabricate(:post)
- TopicAssigner.new(topic, user).assign(user)
- topic
+ assign_to(topic, user)
end
let(:group) { Fabricate(:group).add(user) }
@@ -42,13 +65,10 @@ describe TopicQuery do
],
)
- topic.posts << Fabricate(:post)
- TopicAssigner.new(topic, user).assign(user)
- topic
+ assign_to(topic, user)
end
before do
- SiteSetting.assign_enabled = true
user_topic
assigned_topic
group_assigned_topic
@@ -78,4 +98,11 @@ describe TopicQuery do
).to contain_exactly(assigned_topic, group_assigned_topic)
end
end
+
+ def assign_to(topic, user)
+ topic.tap do |t|
+ t.posts << Fabricate(:post)
+ TopicAssigner.new(t, user).assign(user)
+ end
+ end
end