mirror of
https://github.com/discourse/discourse.git
synced 2024-11-23 02:50:00 +08:00
FEATURE: Use new topic bulk actions dropdown on search page (#27303)
We want to get rid of the old topic bulk actions modal and use the new dropdown (currently gated behind experimental_topic_bulk_actions_enabled_groups). To do this we need to use the new dropdown in all places in the UI. This commit changes the full page search UI to use the new topic bulk actions dropdown if experimental_topic_bulk_actions_enabled_groups is enabled, and makes some minor refactors to make this work. Also add a spec for both the old and new functionality.
This commit is contained in:
parent
0739431cc0
commit
36dbf06fe9
|
@ -6,4 +6,5 @@
|
|||
@action={{fn @performAndRefresh (hash type="append_tags" tags=this.tags)}}
|
||||
@disabled={{not this.tags}}
|
||||
@label="topics.bulk.append_tags"
|
||||
class="topic-bulk-actions__append-tags"
|
||||
/>
|
|
@ -36,7 +36,6 @@ export function addBulkDropdownButton(opts) {
|
|||
|
||||
export default class BulkSelectTopicsDropdown extends Component {
|
||||
@service modal;
|
||||
@service router;
|
||||
@service currentUser;
|
||||
@service siteSettings;
|
||||
|
||||
|
@ -174,7 +173,7 @@ export default class BulkSelectTopicsDropdown extends Component {
|
|||
title,
|
||||
description,
|
||||
bulkSelectHelper: this.args.bulkSelectHelper,
|
||||
refreshClosure: () => this.router.refresh(),
|
||||
refreshClosure: () => this.args.afterBulkActionComplete(),
|
||||
allowSilent,
|
||||
initialAction,
|
||||
initialActionLabel,
|
||||
|
|
|
@ -42,7 +42,7 @@ export default class TopicBulkActions extends Component {
|
|||
{
|
||||
label: "topics.bulk.change_category",
|
||||
icon: "pencil-alt",
|
||||
class: "btn-default",
|
||||
class: "btn-default bulk-actions__change-category",
|
||||
visible: ({ topics }) => !topics.some((t) => t.isPrivateMessage),
|
||||
action({ setComponent }) {
|
||||
setComponent(ChangeCategory);
|
||||
|
@ -60,7 +60,7 @@ export default class TopicBulkActions extends Component {
|
|||
{
|
||||
label: "topics.bulk.archive_topics",
|
||||
icon: "folder",
|
||||
class: "btn-default",
|
||||
class: "btn-default bulk-actions__archive-topics",
|
||||
visible: ({ topics }) => !topics.some((t) => t.isPrivateMessage),
|
||||
action({ forEachPerformed }) {
|
||||
forEachPerformed({ type: "archive" }, (t) => t.set("archived", true));
|
||||
|
@ -69,7 +69,7 @@ export default class TopicBulkActions extends Component {
|
|||
{
|
||||
label: "topics.bulk.archive_topics",
|
||||
icon: "folder",
|
||||
class: "btn-default",
|
||||
class: "btn-default bulk-actions__archive-topics",
|
||||
visible: ({ topics }) => topics.some((t) => t.isPrivateMessage),
|
||||
action: ({ performAndRefresh }) => {
|
||||
const userPrivateMessages = getOwner(this).lookup(
|
||||
|
@ -87,7 +87,7 @@ export default class TopicBulkActions extends Component {
|
|||
{
|
||||
label: "topics.bulk.move_messages_to_inbox",
|
||||
icon: "folder",
|
||||
class: "btn-default",
|
||||
class: "btn-default bulk-actions__move-messages-to-inbox",
|
||||
visible: ({ topics }) => topics.some((t) => t.isPrivateMessage),
|
||||
action: ({ performAndRefresh }) => {
|
||||
const userPrivateMessages = getOwner(this).lookup(
|
||||
|
@ -105,7 +105,7 @@ export default class TopicBulkActions extends Component {
|
|||
{
|
||||
label: "topics.bulk.notification_level",
|
||||
icon: "d-regular",
|
||||
class: "btn-default",
|
||||
class: "btn-default bulk-actions__notification-level",
|
||||
action({ setComponent }) {
|
||||
setComponent(NotificationLevel);
|
||||
},
|
||||
|
@ -113,7 +113,7 @@ export default class TopicBulkActions extends Component {
|
|||
{
|
||||
label: "topics.bulk.defer",
|
||||
icon: "circle",
|
||||
class: "btn-default",
|
||||
class: "btn-default bulk-actions__defer",
|
||||
visible: ({ currentUser }) => currentUser.user_option.enable_defer,
|
||||
action({ performAndRefresh }) {
|
||||
performAndRefresh({ type: "destroy_post_timing" });
|
||||
|
@ -122,7 +122,7 @@ export default class TopicBulkActions extends Component {
|
|||
{
|
||||
label: "topics.bulk.unlist_topics",
|
||||
icon: "far-eye-slash",
|
||||
class: "btn-default",
|
||||
class: "btn-default bulk-actions__unlist",
|
||||
visible: ({ topics }) =>
|
||||
topics.some((t) => t.visible) &&
|
||||
!topics.some((t) => t.isPrivateMessage),
|
||||
|
@ -133,7 +133,7 @@ export default class TopicBulkActions extends Component {
|
|||
{
|
||||
label: "topics.bulk.relist_topics",
|
||||
icon: "far-eye",
|
||||
class: "btn-default",
|
||||
class: "btn-default bulk-actions__relist",
|
||||
visible: ({ topics }) =>
|
||||
topics.some((t) => !t.visible) &&
|
||||
!topics.some((t) => t.isPrivateMessage),
|
||||
|
@ -144,7 +144,7 @@ export default class TopicBulkActions extends Component {
|
|||
{
|
||||
label: "topics.bulk.reset_bump_dates",
|
||||
icon: "anchor",
|
||||
class: "btn-default",
|
||||
class: "btn-default bulk-actions__reset-bump-dates",
|
||||
visible: ({ currentUser }) => currentUser.canManageTopic,
|
||||
action({ performAndRefresh }) {
|
||||
performAndRefresh({ type: "reset_bump_dates" });
|
||||
|
@ -153,7 +153,7 @@ export default class TopicBulkActions extends Component {
|
|||
{
|
||||
label: "topics.bulk.change_tags",
|
||||
icon: "tag",
|
||||
class: "btn-default",
|
||||
class: "btn-default bulk-actions__change-tags",
|
||||
visible: ({ currentUser, siteSettings }) =>
|
||||
siteSettings.tagging_enabled && currentUser.canManageTopic,
|
||||
action({ setComponent }) {
|
||||
|
@ -163,7 +163,7 @@ export default class TopicBulkActions extends Component {
|
|||
{
|
||||
label: "topics.bulk.append_tags",
|
||||
icon: "tag",
|
||||
class: "btn-default",
|
||||
class: "btn-default bulk-actions__append-tags",
|
||||
visible: ({ currentUser, siteSettings }) =>
|
||||
siteSettings.tagging_enabled && currentUser.canManageTopic,
|
||||
action({ setComponent }) {
|
||||
|
@ -173,7 +173,7 @@ export default class TopicBulkActions extends Component {
|
|||
{
|
||||
label: "topics.bulk.remove_tags",
|
||||
icon: "tag",
|
||||
class: "btn-default",
|
||||
class: "btn-default bulk-actions__remove-tags",
|
||||
visible: ({ currentUser, siteSettings }) =>
|
||||
siteSettings.tagging_enabled && currentUser.canManageTopic,
|
||||
action: ({ performAndRefresh, topics }) => {
|
||||
|
@ -188,7 +188,7 @@ export default class TopicBulkActions extends Component {
|
|||
{
|
||||
label: "topics.bulk.delete",
|
||||
icon: "trash-alt",
|
||||
class: "btn-danger delete-topics",
|
||||
class: "btn-danger delete-topics bulk-actions__delete",
|
||||
visible: ({ currentUser }) => currentUser.staff,
|
||||
action({ performAndRefresh }) {
|
||||
performAndRefresh({ type: "delete" });
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
</a>
|
||||
</div>
|
||||
|
||||
<div class="fps-topic">
|
||||
<div class="fps-topic" data-topic-id={{this.post.topic.id}}>
|
||||
<div class="topic">
|
||||
{{#if this.bulkSelectEnabled}}
|
||||
<TrackSelected
|
||||
|
|
|
@ -9,7 +9,10 @@ const TopicBulkSelectDropdown = <template>
|
|||
count=@bulkSelectHelper.selected.length
|
||||
}}
|
||||
</span>
|
||||
<BulkSelectTopicsDropdown @bulkSelectHelper={{@bulkSelectHelper}} />
|
||||
<BulkSelectTopicsDropdown
|
||||
@bulkSelectHelper={{@bulkSelectHelper}}
|
||||
@afterBulkActionComplete={{@afterBulkActionComplete}}
|
||||
/>
|
||||
</div>
|
||||
</template>;
|
||||
|
||||
|
|
|
@ -72,6 +72,11 @@ export default class TopicListHeaderColumn extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
@action
|
||||
afterBulkActionComplete() {
|
||||
return this.router.refresh();
|
||||
}
|
||||
|
||||
<template>
|
||||
<th
|
||||
{{(if @sortable (modifier on "click" this.onClick))}}
|
||||
|
@ -108,6 +113,7 @@ export default class TopicListHeaderColumn extends Component {
|
|||
{{#if @experimentalTopicBulkActionsEnabled}}
|
||||
<TopicBulkSelectDropdown
|
||||
@bulkSelectHelper={{@bulkSelectHelper}}
|
||||
@afterBulkActionComplete={{this.afterBulkActionComplete}}
|
||||
/>
|
||||
{{else}}
|
||||
<button
|
||||
|
|
|
@ -6,6 +6,7 @@ import { isEmpty } from "@ember/utils";
|
|||
import { Promise } from "rsvp";
|
||||
import TopicBulkActions from "discourse/components/modal/topic-bulk-actions";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import BulkSelectHelper from "discourse/lib/bulk-select-helper";
|
||||
import { search as searchCategoryTag } from "discourse/lib/category-tag-search";
|
||||
import { setTransient } from "discourse/lib/page-tracker";
|
||||
import {
|
||||
|
@ -59,6 +60,7 @@ export default Controller.extend({
|
|||
appEvents: service(),
|
||||
siteSettings: service(),
|
||||
searchPreferencesManager: service(),
|
||||
currentUser: service(),
|
||||
|
||||
bulkSelectEnabled: null,
|
||||
loading: false,
|
||||
|
@ -82,7 +84,6 @@ export default Controller.extend({
|
|||
resultCount: null,
|
||||
searchTypes: null,
|
||||
additionalSearchResults: [],
|
||||
selected: [],
|
||||
error: null,
|
||||
|
||||
init() {
|
||||
|
@ -113,6 +114,8 @@ export default Controller.extend({
|
|||
});
|
||||
|
||||
this.set("searchTypes", searchTypes);
|
||||
|
||||
this.bulkSelectHelper = new BulkSelectHelper(this);
|
||||
},
|
||||
|
||||
@discourseComputed("resultCount")
|
||||
|
@ -229,6 +232,11 @@ export default Controller.extend({
|
|||
}
|
||||
},
|
||||
|
||||
@discourseComputed("currentUser.use_experimental_topic_bulk_actions")
|
||||
useNewBulkActions() {
|
||||
return this.currentUser?.use_experimental_topic_bulk_actions;
|
||||
},
|
||||
|
||||
@discourseComputed("q")
|
||||
showLikeCount(q) {
|
||||
return q?.includes("order:likes");
|
||||
|
@ -282,9 +290,12 @@ export default Controller.extend({
|
|||
return this.currentUser && this.currentUser.staff && hasResults;
|
||||
},
|
||||
|
||||
hasSelection: gt("selected.length", 0),
|
||||
hasSelection: gt("bulkSelectHelper.selected.length", 0),
|
||||
|
||||
@discourseComputed("selected.length", "searchResultPosts.length")
|
||||
@discourseComputed(
|
||||
"bulkSelectHelper.selected.length",
|
||||
"searchResultPosts.length"
|
||||
)
|
||||
hasUnselectedResults(selectionCount, postsCount) {
|
||||
return selectionCount < postsCount;
|
||||
},
|
||||
|
@ -350,7 +361,7 @@ export default Controller.extend({
|
|||
if (args.page === 1) {
|
||||
this.set("bulkSelectEnabled", false);
|
||||
|
||||
this.selected.clear();
|
||||
this.bulkSelectHelper.selected.clear();
|
||||
this.set("searching", true);
|
||||
scrollTop();
|
||||
} else {
|
||||
|
@ -465,8 +476,13 @@ export default Controller.extend({
|
|||
searching: false,
|
||||
page: 1,
|
||||
resultCount: null,
|
||||
selected: [],
|
||||
});
|
||||
this.bulkSelectHelper.clear();
|
||||
},
|
||||
|
||||
@action
|
||||
afterBulkActionComplete() {
|
||||
return Promise.resolve(this._search());
|
||||
},
|
||||
|
||||
@action
|
||||
|
@ -502,7 +518,9 @@ export default Controller.extend({
|
|||
|
||||
actions: {
|
||||
selectAll() {
|
||||
this.selected.addObjects(this.get("searchResultPosts").mapBy("topic"));
|
||||
this.bulkSelectHelper.selected.addObjects(
|
||||
this.get("searchResultPosts").mapBy("topic")
|
||||
);
|
||||
|
||||
// Doing this the proper way is a HUGE pain,
|
||||
// we can hack this to work by observing each on the array
|
||||
|
@ -517,7 +535,7 @@ export default Controller.extend({
|
|||
},
|
||||
|
||||
clearAll() {
|
||||
this.selected.clear();
|
||||
this.bulkSelectHelper.selected.clear();
|
||||
|
||||
document
|
||||
.querySelectorAll(".fps-result input[type=checkbox]")
|
||||
|
@ -528,13 +546,13 @@ export default Controller.extend({
|
|||
|
||||
toggleBulkSelect() {
|
||||
this.toggleProperty("bulkSelectEnabled");
|
||||
this.selected.clear();
|
||||
this.bulkSelectHelper.selected.clear();
|
||||
},
|
||||
|
||||
showBulkActions() {
|
||||
this.modal.show(TopicBulkActions, {
|
||||
model: {
|
||||
topics: this.selected,
|
||||
topics: this.bulkSelectHelper.selected,
|
||||
refreshClosure: this._search,
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,13 +1,21 @@
|
|||
import EmberObject from "@ember/object";
|
||||
import EmberObject, { action } from "@ember/object";
|
||||
import { service } from "@ember/service";
|
||||
import BulkSelectTopicsDropdown from "discourse/components/bulk-select-topics-dropdown";
|
||||
import rawRenderGlimmer from "discourse/lib/raw-render-glimmer";
|
||||
import i18n from "discourse-common/helpers/i18n";
|
||||
|
||||
export default class extends EmberObject {
|
||||
@service router;
|
||||
|
||||
get selectedCount() {
|
||||
return this.bulkSelectHelper.selected.length;
|
||||
}
|
||||
|
||||
@action
|
||||
afterBulkAction() {
|
||||
return this.router.refresh();
|
||||
}
|
||||
|
||||
get html() {
|
||||
return rawRenderGlimmer(
|
||||
this,
|
||||
|
@ -18,11 +26,13 @@ export default class extends EmberObject {
|
|||
</span>
|
||||
<BulkSelectTopicsDropdown
|
||||
@bulkSelectHelper={{@data.bulkSelectHelper}}
|
||||
@afterBulkActionComplete={{@data.afterBulkAction}}
|
||||
/>
|
||||
</template>,
|
||||
{
|
||||
bulkSelectHelper: this.bulkSelectHelper,
|
||||
selectedCount: this.selectedCount,
|
||||
afterBulkAction: this.afterBulkAction,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -109,13 +109,20 @@
|
|||
@action={{action "toggleBulkSelect"}}
|
||||
class="btn-default bulk-select"
|
||||
/>
|
||||
{{#if this.selected}}
|
||||
<DButton
|
||||
@selected={{this.selected}}
|
||||
@action={{action "showBulkActions"}}
|
||||
@icon="wrench"
|
||||
class="btn-default bulk-select-btn"
|
||||
/>
|
||||
{{#if this.bulkSelectHelper.selected}}
|
||||
{{#if this.useNewBulkActions}}
|
||||
<TopicList::TopicBulkSelectDropdown
|
||||
@bulkSelectHelper={{this.bulkSelectHelper}}
|
||||
@afterBulkActionComplete={{this.afterBulkActionComplete}}
|
||||
/>
|
||||
{{else}}
|
||||
<DButton
|
||||
@selected={{this.bulkSelectHelper.selected}}
|
||||
@action={{action "showBulkActions"}}
|
||||
@icon="wrench"
|
||||
class="btn-default bulk-select-btn"
|
||||
/>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
|
@ -125,7 +132,7 @@
|
|||
@icon="check-square"
|
||||
@action={{action "selectAll"}}
|
||||
@label="search.select_all"
|
||||
class="btn-default"
|
||||
class="btn-default bulk-select-all"
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
|
@ -134,7 +141,7 @@
|
|||
@icon="far-square"
|
||||
@action={{action "clearAll"}}
|
||||
@label="search.clear_all"
|
||||
class="btn-default"
|
||||
class="btn-default bulk-select-clear"
|
||||
/>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
@ -172,7 +179,7 @@
|
|||
<SearchResultEntries
|
||||
@posts={{this.searchResultPosts}}
|
||||
@bulkSelectEnabled={{this.bulkSelectEnabled}}
|
||||
@selected={{this.selected}}
|
||||
@selected={{this.bulkSelectHelper.selected}}
|
||||
@highlightQuery={{this.highlightQuery}}
|
||||
@searchLogId={{this.model.grouped_search_result.search_log_id}}
|
||||
/>
|
||||
|
|
|
@ -32,10 +32,6 @@ module PageObjects
|
|||
find(bulk_select_dropdown_item(name)).click
|
||||
end
|
||||
|
||||
def click_close_topics_button
|
||||
find(bulk_select_dropdown_item("close-topics")).click
|
||||
end
|
||||
|
||||
def has_bulk_select_modal?
|
||||
page.has_css?("#discourse-modal-title")
|
||||
end
|
||||
|
|
|
@ -7,6 +7,8 @@ describe "Search", type: :system do
|
|||
fab!(:topic2) { Fabricate(:topic, title: "Another test topic") }
|
||||
fab!(:post2) { Fabricate(:post, topic: topic2, raw: "This is another test post in a test topic") }
|
||||
|
||||
let(:topic_bulk_actions_modal) { PageObjects::Modals::TopicBulkActions.new }
|
||||
|
||||
describe "when using full page search on mobile" do
|
||||
before do
|
||||
SearchIndexer.enable
|
||||
|
@ -127,4 +129,65 @@ describe "Search", type: :system do
|
|||
expect(log.search_type).to eq(SearchLog.search_types[:header])
|
||||
end
|
||||
end
|
||||
|
||||
describe "bulk actions" do
|
||||
fab!(:admin)
|
||||
fab!(:tag1) { Fabricate(:tag) }
|
||||
|
||||
before do
|
||||
SearchIndexer.enable
|
||||
SearchIndexer.index(topic, force: true)
|
||||
SearchIndexer.index(topic2, force: true)
|
||||
sign_in(admin)
|
||||
end
|
||||
|
||||
after { SearchIndexer.disable }
|
||||
|
||||
context "when experimental_topic_bulk_actions_enabled_groups is enabled" do
|
||||
before do
|
||||
SiteSetting.experimental_topic_bulk_actions_enabled_groups =
|
||||
Group::AUTO_GROUPS[:trust_level_1]
|
||||
end
|
||||
|
||||
it "allows the user to perform bulk actions on the topic search results" do
|
||||
visit("/search?q=test")
|
||||
expect(page).to have_content(topic.title)
|
||||
find(".search-info .bulk-select").click
|
||||
find(".fps-result .fps-topic[data-topic-id=\"#{topic.id}\"] .bulk-select input").click
|
||||
find(".search-info .bulk-select-topics-dropdown-trigger").click
|
||||
find(".bulk-select-topics-dropdown-content .append-tags").click
|
||||
expect(topic_bulk_actions_modal).to be_open
|
||||
tag_selector = PageObjects::Components::SelectKit.new(".tag-chooser")
|
||||
tag_selector.search(tag1.name)
|
||||
tag_selector.select_row_by_value(tag1.name)
|
||||
tag_selector.collapse
|
||||
topic_bulk_actions_modal.click_bulk_topics_confirm
|
||||
expect(
|
||||
find(".fps-result .fps-topic[data-topic-id=\"#{topic.id}\"] .discourse-tags"),
|
||||
).to have_content(tag1.name)
|
||||
end
|
||||
end
|
||||
|
||||
context "when experimental_topic_bulk_actions_enabled_groups is not enabled" do
|
||||
before { SiteSetting.experimental_topic_bulk_actions_enabled_groups = "" }
|
||||
|
||||
it "allows the user to perform bulk actions on the topic search results" do
|
||||
visit("/search?q=test")
|
||||
expect(page).to have_content(topic.title)
|
||||
find(".search-info .bulk-select").click
|
||||
find(".fps-result .fps-topic[data-topic-id=\"#{topic.id}\"] .bulk-select input").click
|
||||
find(".search-info .bulk-select-btn").click
|
||||
expect(topic_bulk_actions_modal).to be_open
|
||||
find(".bulk-buttons .bulk-actions__append-tags").click
|
||||
tag_selector = PageObjects::Components::SelectKit.new(".tag-chooser")
|
||||
tag_selector.search(tag1.name)
|
||||
tag_selector.select_row_by_value(tag1.name)
|
||||
tag_selector.collapse
|
||||
find(".topic-bulk-actions__append-tags").click
|
||||
expect(
|
||||
find(".fps-result .fps-topic[data-topic-id=\"#{topic.id}\"] .discourse-tags"),
|
||||
).to have_content(tag1.name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue
Block a user