diff --git a/assets/javascripts/discourse-assign/initializers/extend-for-assigns.js b/assets/javascripts/discourse-assign/initializers/extend-for-assigns.js
index 99fc9c8..8d2df0e 100644
--- a/assets/javascripts/discourse-assign/initializers/extend-for-assigns.js
+++ b/assets/javascripts/discourse-assign/initializers/extend-for-assigns.js
@@ -2,6 +2,7 @@ import { renderAvatar } from "discourse/helpers/user-avatar";
import { withPluginApi } from "discourse/lib/plugin-api";
import discourseComputed from "discourse-common/utils/decorators";
import { iconHTML, iconNode } from "discourse-common/lib/icon-library";
+import { escapeExpression } from "discourse/lib/utilities";
import { h } from "virtual-dom";
import { queryRegistry } from "discourse/widgets/widget";
import { getOwner } from "discourse-common/lib/get-owner";
@@ -586,10 +587,19 @@ function initialize(api) {
api.addDiscoveryQueryParam("assigned", { replace: true, refreshModel: true });
api.addTagsHtmlCallback((topic, params = {}) => {
- const [assignedToUser, assignedToGroup] = Object.values(
- topic.getProperties("assigned_to_user", "assigned_to_group")
+ const [assignedToUser, assignedToGroup, topicNote] = Object.values(
+ topic.getProperties(
+ "assigned_to_user",
+ "assigned_to_group",
+ "assignment_note"
+ )
);
+ const topicAssignee = {
+ assignee: assignedToUser || assignedToGroup,
+ note: topicNote,
+ };
+
let assignedToIndirectly;
if (topic.get("indirectly_assigned_to")) {
assignedToIndirectly = Object.entries(
@@ -603,17 +613,18 @@ function initialize(api) {
}
const assignedTo = []
.concat(
- assignedToUser,
- assignedToGroup,
- assignedToIndirectly.map((assigned) => assigned.assigned_to)
+ topicAssignee,
+ assignedToIndirectly.map((assigned) => ({
+ assignee: assigned.assigned_to,
+ note: assigned.assignment_note,
+ }))
)
- .filter((element) => element)
- .flat()
- .uniqBy((assignee) => assignee.assign_path);
+ .filter(({ assignee }) => assignee)
+ .flat();
if (assignedTo) {
return assignedTo
- .map((assignee) => {
+ .map(({ assignee, note }) => {
let assignedPath;
if (assignee.assignedToPostId) {
assignedPath = `/p/${assignee.assignedToPostId}`;
@@ -629,7 +640,7 @@ function initialize(api) {
: "";
return `<${tagName} class="assigned-to discourse-tag simple" ${href}>
${icon}
- ${name}
+ ${name}
${tagName}>`;
})
.join("");
@@ -769,7 +780,7 @@ function initialize(api) {
}
const target = post || topic;
- target.set("assignment_note", null);
+ target.set("assignment_note", data.assignment_note);
if (data.assigned_type === "User") {
target.set(
"assigned_to_user_id",
diff --git a/lib/assigner.rb b/lib/assigner.rb
index f54e3e6..ec8c801 100644
--- a/lib/assigner.rb
+++ b/lib/assigner.rb
@@ -209,6 +209,8 @@ class ::Assigner
action_code[:user] = topic.assignment.present? ? "reassigned" : "assigned"
action_code[:group] = topic.assignment.present? ? "reassigned_group" : "assigned_group"
+ silent = silent || no_assignee_change?(assign_to)
+
@target.assignment&.destroy!
assignment = @target.create_assignment!(assigned_to_id: assign_to.id, assigned_to_type: type, assigned_by_user_id: @assigned_by.id, topic_id: topic.id, note: note)
@@ -233,7 +235,8 @@ class ::Assigner
post_id: post_target? && @target.id,
post_number: post_target? && @target.post_number,
assigned_type: type,
- assigned_to: serializer.new(assign_to, scope: Guardian.new, root: false).as_json
+ assigned_to: serializer.new(assign_to, scope: Guardian.new, root: false).as_json,
+ assignment_note: note,
},
user_ids: allowed_user_ids
)
@@ -385,7 +388,8 @@ class ::Assigner
topic_id: topic.id,
post_id: post_target? && @target.id,
post_number: post_target? && @target.post_number,
- assigned_type: assignment.assigned_to.is_a?(User) ? "User" : "Group"
+ assigned_type: assignment.assigned_to.is_a?(User) ? "User" : "Group",
+ assignment_note: nil,
},
user_ids: allowed_user_ids
)
@@ -429,4 +433,8 @@ class ::Assigner
assignment&.note == note
end
end
+
+ def no_assignee_change?(assignee)
+ @target.assignment&.assigned_to_id == assignee.id
+ end
end
diff --git a/lib/discourse_assign/helpers.rb b/lib/discourse_assign/helpers.rb
index 8deea1a..cc44bf1 100644
--- a/lib/discourse_assign/helpers.rb
+++ b/lib/discourse_assign/helpers.rb
@@ -30,12 +30,13 @@ module DiscourseAssign
def self.build_indirectly_assigned_to(post_assignments, topic)
post_assignments.map do |post_id, assigned_map|
assigned_to = assigned_map[:assigned_to]
+ note = assigned_map[:assignment_note]
post_number = assigned_map[:post_number]
if (assigned_to.is_a?(User))
- [post_id, { assigned_to: build_assigned_to_user(assigned_to, topic), post_number: post_number }]
+ [post_id, { assigned_to: build_assigned_to_user(assigned_to, topic), post_number: post_number, assignment_note: note }]
elsif assigned_to.is_a?(Group)
- [post_id, { assigned_to: build_assigned_to_group(assigned_to, topic), post_number: post_number }]
+ [post_id, { assigned_to: build_assigned_to_group(assigned_to, topic), post_number: post_number, assignment_note: note }]
end
end.to_h
end
diff --git a/plugin.rb b/plugin.rb
index 1535f5a..e9866cd 100644
--- a/plugin.rb
+++ b/plugin.rb
@@ -430,7 +430,7 @@ after_initialize do
add_to_class(:topic, :indirectly_assigned_to) do
return @indirectly_assigned_to if defined?(@indirectly_assigned_to)
@indirectly_assigned_to = Assignment.where(topic_id: id, target_type: "Post", active: true).includes(:target).inject({}) do |acc, assignment|
- acc[assignment.target_id] = { assigned_to: assignment.assigned_to, post_number: assignment.target.post_number } if assignment.target
+ acc[assignment.target_id] = { assigned_to: assignment.assigned_to, post_number: assignment.target.post_number, assignment_note: assignment.note } if assignment.target
acc
end
end
diff --git a/spec/components/search_spec.rb b/spec/components/search_spec.rb
index 4fa7c12..da3367d 100644
--- a/spec/components/search_spec.rb
+++ b/spec/components/search_spec.rb
@@ -47,13 +47,17 @@ describe Search do
result = Search.execute('in:assigned', guardian: guardian)
serializer = GroupedSearchResultSerializer.new(result, scope: guardian)
indirectly_assigned_to = serializer.as_json[:topics].find { |topic| topic[:id] == post5.topic.id }[:indirectly_assigned_to]
- expect(indirectly_assigned_to).to eq(post5.id => { assigned_to: {
- assign_icon: "user-plus",
- assign_path: "/u/#{user.username}/activity/assigned",
- avatar_template: user.avatar_template,
- name: user.name,
- username: user.username
- }, post_number: post5.post_number })
+ expect(indirectly_assigned_to).to eq(post5.id => {
+ assigned_to: {
+ assign_icon: "user-plus",
+ assign_path: "/u/#{user.username}/activity/assigned",
+ avatar_template: user.avatar_template,
+ name: user.name,
+ username: user.username,
+ },
+ post_number: post5.post_number,
+ assignment_note: nil,
+ })
end
end
end
diff --git a/spec/lib/assigner_spec.rb b/spec/lib/assigner_spec.rb
index 7bb6f80..f3e7038 100644
--- a/spec/lib/assigner_spec.rb
+++ b/spec/lib/assigner_spec.rb
@@ -52,7 +52,7 @@ RSpec.describe Assigner do
it "publishes topic assignment after assign and unassign" do
messages = MessageBus.track_publish('/staff/topic-assignment') do
assigner = described_class.new(topic, moderator_2)
- assigner.assign(moderator)
+ assigner.assign(moderator, note: "tomtom best mom")
assigner.unassign
end
@@ -64,6 +64,7 @@ RSpec.describe Assigner do
post_number: false,
assigned_type: "User",
assigned_to: BasicUserSerializer.new(moderator, scope: Guardian.new, root: false).as_json,
+ assignment_note: "tomtom best mom"
})
expect(messages[1].channel).to eq "/staff/topic-assignment"
@@ -73,6 +74,7 @@ RSpec.describe Assigner do
post_id: false,
post_number: false,
assigned_type: "User",
+ assignment_note: nil
})
end
diff --git a/spec/serializers/topic_view_serializer_spec.rb b/spec/serializers/topic_view_serializer_spec.rb
index f948299..23a25d8 100644
--- a/spec/serializers/topic_view_serializer_spec.rb
+++ b/spec/serializers/topic_view_serializer_spec.rb
@@ -35,4 +35,10 @@ RSpec.describe TopicViewSerializer do
serializer = TopicViewSerializer.new(TopicView.new(topic), scope: guardian)
expect(serializer.as_json[:topic_view][:assignment_note]).to eq("note me down")
end
+
+ it "includes indirectly_assigned_to notes in serializer" do
+ Assigner.new(post, user).assign(user, note: "note me down")
+ serializer = TopicViewSerializer.new(TopicView.new(topic), scope: guardian)
+ expect(serializer.as_json[:topic_view][:indirectly_assigned_to][post.id][:assignment_note]).to eq("note me down")
+ end
end
diff --git a/test/javascripts/acceptance/assigned-topic-test.js b/test/javascripts/acceptance/assigned-topic-test.js
index 90de34c..82cd69a 100644
--- a/test/javascripts/acceptance/assigned-topic-test.js
+++ b/test/javascripts/acceptance/assigned-topic-test.js
@@ -20,12 +20,14 @@ function assignCurrentUserToTopic(needs) {
avatar_template:
"/letter_avatar/eviltrout/{size}/3_f9720745f5ce6dfc2b5641fca999d934.png",
};
+ topic["assignment_note"] = "Shark Doododooo";
topic["indirectly_assigned_to"] = {
2: {
assigned_to: {
name: "Developers",
},
post_number: 2,
+ assignment_note: '',
},
};
return helper.response(topic);
@@ -98,6 +100,16 @@ acceptance("Discourse Assign | Assigned topic", function (needs) {
"shows assignment and indirect assignments in the first post"
);
assert.ok(exists("#post_1 .assigned-to svg.d-icon-user-plus"));
+ assert.equal(
+ query(".discourse-tags .assigned-to[href='/t/28830'] span").title,
+ "Shark Doododooo",
+ "shows topic assign notes"
+ );
+ assert.equal(
+ query(".discourse-tags .assigned-to[href='/p/2'] span").title,
+ '',
+ "shows indirect assign notes"
+ );
assert.ok(
exists("#topic-footer-dropdown-reassign"),
"shows reassign dropdown at the bottom of the topic"