Revert "WIP: Experiemental Bulk Topic Actions Dropdown (#25245)"

This reverts commit 89883b2f51.
This commit is contained in:
Blake Erickson 2024-01-25 11:50:15 -07:00
parent d34a7916c0
commit 0dcdc66f58
19 changed files with 7 additions and 463 deletions

View File

@ -1,160 +0,0 @@
import Component from "@glimmer/component";
import { action } from "@ember/object";
import { inject as service } from "@ember/service";
import { Promise } from "rsvp";
import DButton from "discourse/components/d-button";
import DModal from "discourse/components/d-modal";
import Topic from "discourse/models/topic";
import htmlSafe from "discourse-common/helpers/html-safe";
import i18n from "discourse-common/helpers/i18n";
//import AppendTags from "../bulk-actions/append-tags";
//import ChangeCategory from "../bulk-actions/change-category";
//import ChangeTags from "../bulk-actions/change-tags";
//import NotificationLevel from "../bulk-actions/notification-level";
export default class BulkTopicActions extends Component {
@service router;
async perform(operation) {
this.loading = true;
if (this.args.model.bulkSelectHelper.selected.length > 20) {
this.showProgress = true;
}
try {
return this._processChunks(operation);
} catch {
this.dialog.alert(i18n.t("generic_error"));
} finally {
this.loading = false;
this.processedTopicCount = 0;
this.showProgress = false;
}
}
_generateTopicChunks(allTopics) {
let startIndex = 0;
const chunkSize = 30;
const chunks = [];
while (startIndex < allTopics.length) {
chunks.push(allTopics.slice(startIndex, startIndex + chunkSize));
startIndex += chunkSize;
}
return chunks;
}
_processChunks(operation) {
const allTopics = this.args.model.bulkSelectHelper.selected;
const topicChunks = this._generateTopicChunks(allTopics);
const topicIds = [];
const options = {};
if (this.args.model.allowSilent === true) {
options.silent = true;
}
const tasks = topicChunks.map((topics) => async () => {
const result = await Topic.bulkOperation(topics, operation, options);
this.processedTopicCount += topics.length;
return result;
});
return new Promise((resolve, reject) => {
const resolveNextTask = async () => {
if (tasks.length === 0) {
const topics = topicIds.map((id) => allTopics.findBy("id", id));
return resolve(topics);
}
const task = tasks.shift();
try {
const result = await task();
if (result?.topic_ids) {
topicIds.push(...result.topic_ids);
}
resolveNextTask();
} catch {
reject();
}
};
resolveNextTask();
});
}
@action
setComponent(component) {
this.activeComponent = component;
}
@action
performAction() {
switch (this.args.model.action) {
case "close":
this.forEachPerformed({ type: "close" }, (t) => t.set("closed", true));
break;
}
}
@action
async forEachPerformed(operation, cb) {
const topics = await this.perform(operation);
if (topics) {
topics.forEach(cb);
this.args.model.refreshClosure?.();
this.args.closeModal();
this.args.model.bulkSelectHelper.toggleBulkSelect();
}
}
@action
async performAndRefresh(operation) {
await this.perform(operation);
this.args.model.refreshClosure?.();
this.args.closeModal();
}
<template>
<DModal
@title={{@model.title}}
@closeModal={{@closeModal}}
class="topic-bulk-actions-modal -large"
>
<:body>
<div>
{{htmlSafe (i18n "topics.bulk.selected" count=@model.topics.length)}}
</div>
</:body>
<:footer>
{{#if @model.allowSilent}}
<div class="topic-bulk-actions-options">
<label
for="topic-bulk-action-options__silent"
class="checkbox-label"
>
<input
class=""
id="topic-bulk-action-options__silent"
type="checkbox"
/>{{i18n "topics.bulk.silent"}}</label>
</div>
{{/if}}
<DButton
@action={{this.performAction}}
@icon="check"
@label="topics.bulk.confirm"
id="bulk-topics-confirm"
class="btn-primary"
/>
</:footer>
</DModal>
</template>
}

View File

@ -196,14 +196,6 @@ export default class TopicBulkActions extends Component {
}, },
]; ];
constructor() {
super(...arguments);
if (this.args.model.initialAction === "set-component") {
this.setComponent(this.args.model.initialComponent);
}
}
get buttons() { get buttons() {
return [...this.defaultButtons, ..._customButtons].filter(({ visible }) => { return [...this.defaultButtons, ..._customButtons].filter(({ visible }) => {
if (visible) { if (visible) {

View File

@ -12,8 +12,6 @@
sortable=this.sortable sortable=this.sortable
listTitle=this.listTitle listTitle=this.listTitle
bulkSelectEnabled=this.bulkSelectEnabled bulkSelectEnabled=this.bulkSelectEnabled
bulkSelectHelper=this.bulkSelectHelper
experimentalTopicBulkActionsEnabled=this.experimentalTopicBulkActionsEnabled
canDoBulkActions=this.canDoBulkActions canDoBulkActions=this.canDoBulkActions
showTopicsAndRepliesToggle=this.showTopicsAndRepliesToggle showTopicsAndRepliesToggle=this.showTopicsAndRepliesToggle
newListSubset=this.newListSubset newListSubset=this.newListSubset

View File

@ -48,11 +48,6 @@ export default Component.extend(LoadMore, {
); );
}, },
@discourseComputed
experimentalTopicBulkActionsEnabled() {
return this.currentUser?.use_experimental_topic_bulk_actions;
},
@discourseComputed @discourseComputed
sortable() { sortable() {
return !!this.changeSort; return !!this.changeSort;

View File

@ -49,7 +49,7 @@ export default class BulkSelectHelper {
this.router.currentRoute.queryParams["filter"]) === "tracked"; this.router.currentRoute.queryParams["filter"]) === "tracked";
const promise = this.selected.length const promise = this.selected.length
? Topic.bulkOperation(this.selected, operation, {}, isTracked) ? Topic.bulkOperation(this.selected, operation, isTracked)
: Topic.bulkOperationByFilter("unread", operation, options, isTracked); : Topic.bulkOperationByFilter("unread", operation, options, isTracked);
promise.then((result) => { promise.then((result) => {

View File

@ -806,19 +806,13 @@ Topic.reopenClass({
return promise; return promise;
}, },
bulkOperation(topics, operation, options, tracked) { bulkOperation(topics, operation, tracked) {
const data = { const data = {
topic_ids: topics.mapBy("id"), topic_ids: topics.mapBy("id"),
operation, operation,
tracked, tracked,
}; };
if (options) {
if (options.select) {
data.silent = true;
}
}
return ajax("/topics/bulk", { return ajax("/topics/bulk", {
type: "PUT", type: "PUT",
data, data,

View File

@ -1,22 +1,12 @@
<th data-sort-order='{{order}}' class='{{view.className}} topic-list-data' scope="col" {{#if ariaLabel}}aria-label='{{ariaLabel}}'{{/if}} {{#if sortable}}tabindex="0" role="button" aria-pressed='{{view.ariaPressed}}' {{#if view.ariaSort}}aria-sort='{{view.ariaSort}}'{{/if}} {{/if}}> <th data-sort-order='{{order}}' class='{{view.className}} topic-list-data' scope="col" {{#if ariaLabel}}aria-label='{{ariaLabel}}'{{/if}} {{#if sortable}}tabindex="0" role="button" aria-pressed='{{view.ariaPressed}}' {{#if view.ariaSort}}aria-sort='{{view.ariaSort}}'{{/if}} {{/if}}>
{{~#if canBulkSelect}} {{~#if canBulkSelect}}
{{~#if showBulkToggle}} {{~#if showBulkToggle}}
{{~#if experimentalTopicBulkActionsEnabled }} {{raw "flat-button" class="bulk-select" icon="list" title="topics.bulk.toggle"}}
{{raw "flat-button" class="bulk-select" icon="tasks" title="topics.bulk.toggle"}}
{{else}}
{{raw "flat-button" class="bulk-select" icon="list" title="topics.bulk.toggle"}}
{{/if ~}}
{{/if ~}} {{/if ~}}
{{~#if bulkSelectEnabled}} {{~#if bulkSelectEnabled}}
<span class='bulk-select-topics'> <span class='bulk-select-topics'>
{{~#if canDoBulkActions}} {{~#if canDoBulkActions}}
{{~#if experimentalTopicBulkActionsEnabled }} <button class='btn btn-default btn-icon no-text bulk-select-actions'>{{d-icon "cog"}}&#8203;</button>
{{raw "topic-bulk-select-dropdown" bulkSelectHelper=bulkSelectHelper}}
{{! Just showing both buttons for now for development}}
<button class='btn btn-icon no-text bulk-select-actions'>{{d-icon "cog"}}&#8203;</button>
{{else}}
<button class='btn btn-icon no-text bulk-select-actions'>{{d-icon "cog"}}&#8203;</button>
{{/if ~}}
{{/if ~}} {{/if ~}}
<button class='btn btn-default bulk-select-all'>{{i18n "topics.bulk.select_all"}}</button> <button class='btn btn-default bulk-select-all'>{{i18n "topics.bulk.select_all"}}</button>
<button class='btn btn-default bulk-clear-all'>{{i18n "topics.bulk.clear_all"}}</button> <button class='btn btn-default bulk-clear-all'>{{i18n "topics.bulk.clear_all"}}</button>

View File

@ -2,15 +2,11 @@
{{#if bulkSelectEnabled}} {{#if bulkSelectEnabled}}
<th class="bulk-select topic-list-data"> <th class="bulk-select topic-list-data">
{{#if canBulkSelect}} {{#if canBulkSelect}}
{{#if experimentalTopicBulkActionsEnabled }} {{raw "flat-button" class="bulk-select" icon="list" title="topics.bulk.toggle"}}
{{raw "flat-button" class="bulk-select" icon="tasks" title="topics.bulk.toggle"}}
{{else}}
{{raw "flat-button" class="bulk-select" icon="list" title="topics.bulk.toggle"}}
{{/if}}
{{/if}} {{/if}}
</th> </th>
{{/if}} {{/if}}
{{raw "topic-list-header-column" order='default' name=listTitle bulkSelectEnabled=bulkSelectEnabled showBulkToggle=toggleInTitle canBulkSelect=canBulkSelect canDoBulkActions=canDoBulkActions showTopicsAndRepliesToggle=showTopicsAndRepliesToggle newListSubset=newListSubset newRepliesCount=newRepliesCount newTopicsCount=newTopicsCount experimentalTopicBulkActionsEnabled=experimentalTopicBulkActionsEnabled bulkSelectHelper=bulkSelectHelper }} {{raw "topic-list-header-column" order='default' name=listTitle bulkSelectEnabled=bulkSelectEnabled showBulkToggle=toggleInTitle canBulkSelect=canBulkSelect canDoBulkActions=canDoBulkActions showTopicsAndRepliesToggle=showTopicsAndRepliesToggle newListSubset=newListSubset newRepliesCount=newRepliesCount newTopicsCount=newTopicsCount}}
{{raw-plugin-outlet name="topic-list-header-after-main-link"}} {{raw-plugin-outlet name="topic-list-header-after-main-link"}}
{{#if showPosters}} {{#if showPosters}}
{{raw "topic-list-header-column" order='posters' ariaLabel=(i18n "category.sort_options.posters")}} {{raw "topic-list-header-column" order='posters' ariaLabel=(i18n "category.sort_options.posters")}}

View File

@ -1,26 +0,0 @@
import EmberObject from "@ember/object";
import rawRenderGlimmer from "discourse/lib/raw-render-glimmer";
import BulkSelectTopicsDropdown from "select-kit/components/bulk-select-topics-dropdown";
export default class extends EmberObject {
get selectedCount() {
return this.bulkSelectHelper.selected.length;
}
get html() {
return rawRenderGlimmer(
this,
"div.bulk-select-topics-dropdown",
<template>
<span>{{@data.selectedCount}} selected</span>
<BulkSelectTopicsDropdown
@bulkSelectHelper={{@data.bulkSelectHelper}}
/>
</template>,
{
bulkSelectHelper: this.bulkSelectHelper,
selectedCount: this.selectedCount,
}
);
}
}

View File

@ -1,68 +0,0 @@
import { action } from "@ember/object";
import { inject as service } from "@ember/service";
import ChangeCategory from "discourse/components/bulk-actions/change-category";
import BulkTopicActions from "discourse/components/modal/bulk-topic-actions";
import TopicBulkActions from "discourse/components/modal/topic-bulk-actions";
import i18n from "discourse-common/helpers/i18n";
import DropdownSelectBoxComponent from "select-kit/components/dropdown-select-box";
export default DropdownSelectBoxComponent.extend({
classNames: ["bulk-select-topics-dropdown"],
headerIcon: null,
showFullTitle: true,
selectKitOptions: {
showCaret: true,
showFullTitle: true,
none: "select_kit.components.bulk_select_topics_dropdown.title",
},
modal: service(),
router: service(),
computeContent() {
let options = [];
options = options.concat([
{
id: "update-category",
icon: "pencil-alt",
name: i18n("topic_bulk_actions.update_category.name"),
description: i18n("topic_bulk_actions.update_category.description"),
},
{
id: "close-topics",
icon: "lock",
name: i18n("topic_bulk_actions.close_topics.name"),
},
]);
return options;
},
@action
onSelect(id) {
switch (id) {
case "update-category":
// Temporary: just use the existing modal & action
this.modal.show(TopicBulkActions, {
model: {
topics: this.bulkSelectHelper.selected,
category: this.category,
refreshClosure: () => this.router.refresh(),
initialAction: "set-component",
initialComponent: ChangeCategory,
},
});
break;
case "close-topics":
this.modal.show(BulkTopicActions, {
model: {
action: "close",
title: i18n("topics.bulk.close_topics"),
bulkSelectHelper: this.bulkSelectHelper,
refreshClosure: () => this.router.refresh(),
allowSilent: true,
},
});
break;
}
},
});

View File

@ -218,20 +218,6 @@
} }
} }
.d-modal.topic-bulk-actions-modal {
.d-modal {
&__container {
display: flex;
}
}
p {
margin-top: 0;
}
#bulk-topics-confirm {
margin-left: auto;
}
}
.d-modal.edit-slow-mode-modal { .d-modal.edit-slow-mode-modal {
.slow-mode-label { .slow-mode-label {
display: inline-flex; display: inline-flex;

View File

@ -200,22 +200,6 @@
} }
} }
.arrow {
border: solid white;
border-width: 0 3px 3px 0;
display: inline-block;
padding: 3px;
margin-left: 4px;
}
.down {
transform: rotate(45deg);
-webkit-transform: rotate(45deg);
}
.bulk-select-actions {
}
.dismiss-container-top { .dismiss-container-top {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;

View File

@ -66,8 +66,7 @@ class CurrentUserSerializer < BasicUserSerializer
:sidebar_tags, :sidebar_tags,
:sidebar_category_ids, :sidebar_category_ids,
:sidebar_sections, :sidebar_sections,
:new_new_view_enabled?, :new_new_view_enabled?
:use_experimental_topic_bulk_actions?
delegate :user_stat, to: :object, private: true delegate :user_stat, to: :object, private: true
delegate :any_posts, :draft_count, :pending_posts_count, :read_faq?, to: :user_stat delegate :any_posts, :draft_count, :pending_posts_count, :read_faq?, to: :user_stat
@ -278,8 +277,4 @@ class CurrentUserSerializer < BasicUserSerializer
def unseen_reviewable_count def unseen_reviewable_count
Reviewable.unseen_reviewable_count(object) Reviewable.unseen_reviewable_count(object)
end end
def use_experimental_topic_bulk_actions?
scope.user.in_any_groups?(SiteSetting.experimental_topic_bulk_actions_enabled_groups_map)
end
end end

View File

@ -2349,8 +2349,6 @@ en:
filter_for_more: Filter for more… filter_for_more: Filter for more…
categories_admin_dropdown: categories_admin_dropdown:
title: "Manage categories" title: "Manage categories"
bulk_select_topics_dropdown:
title: "Bulk Actions"
date_time_picker: date_time_picker:
from: From from: From
@ -2888,7 +2886,6 @@ en:
topics: topics:
new_messages_marker: "last visit" new_messages_marker: "last visit"
bulk: bulk:
confirm: "Confirm"
select_all: "Select All" select_all: "Select All"
clear_all: "Clear All" clear_all: "Clear All"
unlist_topics: "Unlist Topics" unlist_topics: "Unlist Topics"
@ -2947,7 +2944,6 @@ en:
progress: progress:
one: "Progress: <strong>%{count}</strong> topic" one: "Progress: <strong>%{count}</strong> topic"
other: "Progress: <strong>%{count}</strong> topics" other: "Progress: <strong>%{count}</strong> topics"
silent: "Perform this action silently."
none: none:
unread: "You have no unread topics." unread: "You have no unread topics."
@ -2979,13 +2975,6 @@ en:
bookmarks: "There are no more bookmarked topics." bookmarks: "There are no more bookmarked topics."
filter: "There are no more topics." filter: "There are no more topics."
topic_bulk_actions:
close_topics:
name: "Close Topics"
update_category:
name: "Update Category"
description: "Choose the new category for the selected topics"
topic: topic:
filter_to: filter_to:
one: "%{count} post in topic" one: "%{count} post in topic"

View File

@ -2355,13 +2355,6 @@ developer:
default: "" default: ""
client: true client: true
hidden: true hidden: true
experimental_topic_bulk_actions_enabled_groups:
default: ""
hidden: true
type: group_list
list_type: compact
allow_any: false
refresh: true
navigation: navigation:
navigation_menu: navigation_menu:

View File

@ -30,18 +30,6 @@ module PageObjects
page.has_no_css?(topic_list_item_class(topic)) page.has_no_css?(topic_list_item_class(topic))
end end
def has_topic_checkbox?(topic)
page.has_css?("#{topic_list_item_class(topic)} input#bulk-select-#{topic.id}")
end
def has_closed_status?(topic)
page.has_css?("#{topic_list_item_closed(topic)}")
end
def click_topic_checkbox(topic)
find("#{topic_list_item_class(topic)} input#bulk-select-#{topic.id}").click
end
def visit_topic_with_title(title) def visit_topic_with_title(title)
find("#{TOPIC_LIST_BODY_SELECTOR} a", text: title).click find("#{TOPIC_LIST_BODY_SELECTOR} a", text: title).click
end end
@ -64,10 +52,6 @@ module PageObjects
def topic_list_item_class(topic) def topic_list_item_class(topic)
"#{TOPIC_LIST_ITEM_SELECTOR}[data-topic-id='#{topic.id}']" "#{TOPIC_LIST_ITEM_SELECTOR}[data-topic-id='#{topic.id}']"
end end
def topic_list_item_closed(topic)
"#{topic_list_item_class(topic)} .topic-statuses .topic-status svg.locked"
end
end end
end end
end end

View File

@ -1,56 +0,0 @@
# frozen_string_literal: true
module PageObjects
module Components
class TopicListHeader < PageObjects::Components::Base
TOPIC_LIST_HEADER_SELECTOR = ".topic-list .topic-list-header"
TOPIC_LIST_DATA_SELECTOR = "#{TOPIC_LIST_HEADER_SELECTOR} .topic-list-data"
def topic_list_header
TOPIC_LIST_HEADER_SELECTOR
end
def has_bulk_select_button?
page.has_css?("#{TOPIC_LIST_HEADER_SELECTOR} button.bulk-select")
end
def click_bulk_select_button
find("#{TOPIC_LIST_HEADER_SELECTOR} button.bulk-select").click
end
def has_bulk_select_topics_dropdown?
page.has_css?(
"#{TOPIC_LIST_HEADER_SELECTOR} .bulk-select-topics div.bulk-select-topics-dropdown",
)
end
def click_bulk_select_topics_dropdown
find(
"#{TOPIC_LIST_HEADER_SELECTOR} .bulk-select-topics div.bulk-select-topics-dropdown",
).click
end
def has_close_topics_button?
page.has_css?(bulk_select_dropdown_item("close-topics"))
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
def click_bulk_topics_confirm
find("#bulk-topics-confirm").click
end
private
def bulk_select_dropdown_item(name)
"#{TOPIC_LIST_HEADER_SELECTOR} .bulk-select-topics div.bulk-select-topics-dropdown li[data-value='#{name}']"
end
end
end
end

View File

@ -1,41 +0,0 @@
# frozen_string_literal: true
describe "Topic bulk select", type: :system do
before { SiteSetting.experimental_topic_bulk_actions_enabled_groups = "1" }
fab!(:topics) { Fabricate.times(10, :post).map(&:topic) }
let(:topic_list_header) { PageObjects::Components::TopicListHeader.new }
let(:topic_list) { PageObjects::Components::TopicList.new }
context "when in topic" do
fab!(:admin)
before { sign_in(admin) }
it "closes multiple topics" do
visit("/latest")
expect(page).to have_css(".topic-list button.bulk-select")
expect(topic_list_header).to have_bulk_select_button
# Click bulk select button
topic_list_header.click_bulk_select_button
expect(topic_list).to have_topic_checkbox(topics.first)
# Select Topics
topic_list.click_topic_checkbox(topics.first)
topic_list.click_topic_checkbox(topics.second)
# Has Dropdown
expect(topic_list_header).to have_bulk_select_topics_dropdown
topic_list_header.click_bulk_select_topics_dropdown
# Clicking the close button opens up the modal
expect(topic_list_header).to have_close_topics_button
topic_list_header.click_close_topics_button
expect(topic_list_header).to have_bulk_select_modal
# Closes the selected topics
topic_list_header.click_bulk_topics_confirm
expect(topic_list).to have_closed_status(topics.first)
end
end
end