FEATURE: Assign bulk actions for topics lists (#110)

- Allows unassigning and reassigning topics using bulk actions
- Adds bulk actions UI to the group assigned page
This commit is contained in:
Ahmed Gagan 2020-09-11 16:19:25 +05:30 committed by GitHub
parent e6a3bc80d7
commit 3e3dc3815b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 177 additions and 2 deletions

View File

@ -1,7 +1,9 @@
import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error";
import { inject as controller } from "@ember/controller";
export default Ember.Controller.extend({
topicBulkActions: controller(),
assignSuggestions: null,
allowedGroups: null,
taskActions: Ember.inject.service(),
@ -22,8 +24,19 @@ export default Ember.Controller.extend({
}
},
bulkAction(username) {
this.topicBulkActions.performAndRefresh({
type: "assign",
username,
});
},
actions: {
assignUser(user) {
if (this.isBulkAction) {
this.bulkAction(user.username);
return;
}
this.setProperties({
"model.username": user.username,
"model.allowedGroups": this.taskActions.allowedGroups,
@ -32,6 +45,10 @@ export default Ember.Controller.extend({
},
assign() {
if (this.isBulkAction) {
this.bulkAction(this.model.username);
return;
}
let path = "/assign/assign";
if (Ember.isEmpty(this.get("model.username"))) {

View File

@ -1,4 +1,5 @@
import UserTopicsList from "discourse/controllers/user-topics-list";
import { alias } from "@ember/object/computed";
import { debounce } from "@ember/runloop";
import discourseComputed from "discourse-common/utils/decorators";
import { INPUT_DELAY } from "discourse-common/config/environment";
@ -9,6 +10,9 @@ export default UserTopicsList.extend({
order: null,
ascending: false,
q: "",
bulkSelectEnabled: false,
selected: [],
canBulkSelect: alias("currentUser.staff"),
queryParams: ["order", "ascending", "q"],
@ -61,5 +65,11 @@ export default UserTopicsList.extend({
onChangeFilter(value) {
debounce(this, this._setSearchTerm, value, INPUT_DELAY * 2);
},
toggleBulkSelect() {
this.toggleProperty("bulkSelectEnabled");
},
refresh() {
this.refreshModel();
},
},
});

View File

@ -7,6 +7,9 @@ import { queryRegistry } from "discourse/widgets/widget";
import { getOwner } from "discourse-common/lib/get-owner";
import { htmlSafe } from "@ember/template";
import getURL from "discourse-common/lib/get-url";
import { addBulkButton } from "discourse/controllers/topic-bulk-actions";
import TopicButtonAction from "discourse/controllers/topic-bulk-actions";
import { inject } from "@ember/controller";
import I18n from "I18n";
function titleForState(user) {
@ -320,6 +323,30 @@ export default {
return;
}
const currentUser = container.lookup("current-user:main");
if (currentUser.can_assign) {
TopicButtonAction.reopen({
assignUser: inject("assign-user"),
actions: {
showReAssign() {
this.set("assignUser.isBulkAction", true);
this.set("assignUser.model", { username: "" });
this.send("changeBulkTemplate", "modal/assign-user");
},
unassignTopics() {
this.performAndRefresh({ type: "unassign" });
},
},
});
addBulkButton("showReAssign", "assign", {
icon: "user-plus",
class: "btn-default",
});
addBulkButton("unassignTopics", "unassign", {
icon: "user-times",
class: "btn-default",
});
}
withPluginApi("0.8.11", (api) => initialize(api, container));
withPluginApi("0.8.28", (api) =>
registerTopicFooterButtons(api, container)

View File

@ -5,8 +5,13 @@
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.
--}}
<td class="main-link clearfix" colspan="1">
<span class="link-top-line">
{{#if bulkSelectEnabled}}
<td class="bulk-select">
<input type="checkbox" class="bulk-select">
</td>
{{/if}}
<td class='main-link clearfix' colspan="1">
<span class='link-top-line'>
{{~raw "topic-status" topic=topic}}
{{~#if isPrivateMessage}}
{{~d-icon "envelope" class="private-message-icon"}}

View File

@ -1,6 +1,7 @@
{{#unless skipHeader}}
<thead>
{{raw "topic-list-header"
canBulkSelect=canBulkSelect
toggleInTitle=toggleInTitle
hideCategory=hideCategory
showPosters=showPosters
@ -17,6 +18,7 @@
<tbody>
{{#each filteredTopics as |topic|}}
{{assigned-topic-list-item topic=topic
bulkSelectEnabled=bulkSelectEnabled
showTopicPostBadges=showTopicPostBadges
hideCategory=hideCategory
showPosters=showPosters

View File

@ -14,10 +14,13 @@
hideCategory=hideCategory
topics=topics
expandExcerpts=expandExcerpts
bulkSelectEnabled=bulkSelectEnabled
canBulkSelect=canBulkSelect
selected=selected
skipHeader=skipHeader
tagsForUser=tagsForUser
changeSort=changeSort
toggleBulkSelect=toggleBulkSelect
unassign=unassign
reassign=reassign
onScroll=onScroll

View File

@ -8,17 +8,23 @@
</div>
</div>
{{#load-more class="paginated-topics-list" selector=".paginated-topics-list .topic-list tr" action=(action "loadMore")}}
{{bulk-select-button
selected=selected
action=(action "refresh")
}}
{{basic-assigned-topic-list
topicList=model
hideCategory=hideCategory
showPosters=showPosters
bulkSelectEnabled=bulkSelectEnabled
canBulkSelect=canBulkSelect
selected=selected
hasIncoming=hasIncoming
incomingCount=incomingCount
showInserted=(action "showInserted")
tagsForUser=tagsForUser
changeSort=(action "changeSort")
toggleBulkSelect=(action "toggleBulkSelect")
unassign=(action "unassign")
reassign=(action "reassign")
onScroll=saveScrollPosition

View File

@ -53,3 +53,7 @@ en:
assign_event:
name: "Assign Event"
details: "When a user assigns or unassigns a topic."
topics:
bulk:
unassign: "Unassign Topics"
assign: "Assign Topics"

View File

@ -398,6 +398,29 @@ after_initialize do
end
end
TopicsBulkAction.register_operation("assign") do
if @user.can_assign?
assign_user = User.find_by_username(@operation[:username])
topics.each do |t|
TopicAssigner.new(t, @user).assign(assign_user)
end
end
end
TopicsBulkAction.register_operation("unassign") do
if @user.can_assign?
topics.each do |t|
if guardian.can_assign?
TopicAssigner.new(t, @user).unassign
end
end
end
end
if defined? register_permitted_bulk_action_parameter
register_permitted_bulk_action_parameter :username
end
if defined? UserBookmarkSerializer
add_to_class(:user_bookmark_serializer, :assigned_to_user_id) do
id = topic.custom_fields[TopicAssigner::ASSIGNED_TO_ID]

View File

@ -0,0 +1,78 @@
# frozen_string_literal: true
require 'rails_helper'
require_relative '../support/assign_allowed_group'
describe TopicsBulkAction do
fab!(:post) { Fabricate(:post) }
fab!(:post1) { Fabricate(:post) }
fab!(:post2) { Fabricate(:post) }
before do
SiteSetting.assign_enabled = true
end
let(:user) { Fabricate(:user) }
let(:user2) { Fabricate(:user) }
include_context 'A group that is allowed to assign'
before do
add_to_assign_allowed_group(user)
end
describe "assign_topics" do
it "assigns multiple topics to user" do
TopicsBulkAction.new(user, [post.topic.id, post1.topic.id], { type: 'assign', username: user.username }).perform!
assigned_topics = TopicQuery.new(user, { page: 0 }).list_messages_assigned(user).topics
expect(assigned_topics.length).to eq(2)
expect(assigned_topics).to contain_exactly(post.topic, post1.topic)
end
it "doesn't allows to assign to user not in assign_allowed_group" do
TopicsBulkAction.new(user, [post.topic.id, post1.topic.id], { type: 'assign', username: user2.username }).perform!
assigned_topics = TopicQuery.new(user, { page: 0 }).list_messages_assigned(user2).topics
expect(assigned_topics.length).to eq(0)
end
it "user who is not in assign_allowed_group can't assign topics" do
TopicsBulkAction.new(user2, [post.topic.id, post1.topic.id, post2.topic.id], { type: 'assign', username: user.username }).perform!
assigned_topics = TopicQuery.new(user, { page: 0 }).list_messages_assigned(user).topics
expect(assigned_topics.length).to eq(0)
end
end
describe "unassign_topics" do
it "unassigns multiple topics assigned to user" do
TopicsBulkAction.new(user, [post.topic.id, post1.topic.id, post2.topic.id], { type: 'assign', username: user.username }).perform!
TopicsBulkAction.new(user, [post.topic.id, post1.topic.id], type: 'unassign').perform!
assigned_topics = TopicQuery.new(user, { page: 0 }).list_messages_assigned(user).topics
expect(assigned_topics.length).to eq(1)
expect(assigned_topics).to contain_exactly(post2.topic)
end
it "user who is not in assign_allowed_group can't unassign topics" do
TopicsBulkAction.new(user, [post.topic.id, post1.topic.id, post2.topic.id], { type: 'assign', username: user.username }).perform!
TopicsBulkAction.new(user2, [post.topic.id, post1.topic.id], type: 'unassign').perform!
assigned_topics = TopicQuery.new(user, { page: 0 }).list_messages_assigned(user).topics
expect(assigned_topics.length).to eq(3)
expect(assigned_topics).to contain_exactly(post.topic, post1.topic, post2.topic)
end
end
end