DEV: Refactor gjs topic-list (#29792)

Based on the initial review in #28934
This commit is contained in:
Jarek Radosz 2024-11-25 14:15:34 +01:00 committed by GitHub
parent bfe0eccdd9
commit 433543a516
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 375 additions and 254 deletions

View File

@ -0,0 +1,26 @@
const Header = <template>
<tr>
{{#each @columns as |entry|}}
<entry.value.header
@sortable={{@sortable}}
@activeOrder={{@order}}
@changeSort={{@changeSort}}
@ascending={{@ascending}}
@category={{@category}}
@name={{@listTitle}}
@bulkSelectEnabled={{@bulkSelectEnabled}}
@showBulkToggle={{@toggleInTitle}}
@canBulkSelect={{@canBulkSelect}}
@canDoBulkActions={{@canDoBulkActions}}
@showTopicsAndRepliesToggle={{@showTopicsAndRepliesToggle}}
@newListSubset={{@newListSubset}}
@newRepliesCount={{@newRepliesCount}}
@newTopicsCount={{@newTopicsCount}}
@bulkSelectHelper={{@bulkSelectHelper}}
@changeNewListSubset={{@changeNewListSubset}}
/>
{{/each}}
</tr>
</template>;
export default Header;

View File

@ -0,0 +1,15 @@
import SortableColumn from "./sortable-column";
const ActivityCell = <template>
<SortableColumn
@sortable={{@sortable}}
@number="true"
@order="activity"
@activeOrder={{@activeOrder}}
@changeSort={{@changeSort}}
@ascending={{@ascending}}
@name="activity"
/>
</template>;
export default ActivityCell;

View File

@ -0,0 +1,19 @@
import { on } from "@ember/modifier";
import icon from "discourse-common/helpers/d-icon";
import { i18n } from "discourse-i18n";
const BulkSelectCell = <template>
<th class="bulk-select topic-list-data">
{{#if @canBulkSelect}}
<button
{{on "click" @bulkSelectHelper.toggleBulkSelect}}
title={{i18n "topics.bulk.toggle"}}
class="btn-flat bulk-select"
>
{{icon "list-check"}}
</button>
{{/if}}
</th>
</template>;
export default BulkSelectCell;

View File

@ -0,0 +1,15 @@
import SortableColumn from "./sortable-column";
const LikesCell = <template>
<SortableColumn
@sortable={{@sortable}}
@number="true"
@order="likes"
@activeOrder={{@activeOrder}}
@changeSort={{@changeSort}}
@ascending={{@ascending}}
@name="likes"
/>
</template>;
export default LikesCell;

View File

@ -0,0 +1,15 @@
import SortableColumn from "./sortable-column";
const OpLikesCell = <template>
<SortableColumn
@sortable={{@sortable}}
@number="true"
@order="op_likes"
@activeOrder={{@activeOrder}}
@changeSort={{@changeSort}}
@ascending={{@ascending}}
@name="likes"
/>
</template>;
export default OpLikesCell;

View File

@ -0,0 +1,16 @@
import { i18n } from "discourse-i18n";
import SortableColumn from "./sortable-column";
const PostersCell = <template>
<SortableColumn
@order="posters"
@activeOrder={{@activeOrder}}
@changeSort={{@changeSort}}
@ascending={{@ascending}}
@name="posters"
@screenreaderOnly={{true}}
aria-label={{i18n "category.sort_options.posters"}}
/>
</template>;
export default PostersCell;

View File

@ -0,0 +1,15 @@
import SortableColumn from "./sortable-column";
const RepliesCell = <template>
<SortableColumn
@sortable={{@sortable}}
@number="true"
@order="posts"
@activeOrder={{@activeOrder}}
@changeSort={{@changeSort}}
@ascending={{@ascending}}
@name="replies"
/>
</template>;
export default RepliesCell;

View File

@ -10,7 +10,7 @@ import concatClass from "discourse/helpers/concat-class";
import icon from "discourse-common/helpers/d-icon"; import icon from "discourse-common/helpers/d-icon";
import { i18n } from "discourse-i18n"; import { i18n } from "discourse-i18n";
export default class TopicListHeaderColumn extends Component { export default class SortableColumn extends Component {
@service router; @service router;
get localizedName() { get localizedName() {
@ -49,7 +49,8 @@ export default class TopicListHeaderColumn extends Component {
} }
@action @action
onClick() { onClick(event) {
event.preventDefault();
this.args.changeSort(this.args.order); this.args.changeSort(this.args.order);
} }

View File

@ -0,0 +1,24 @@
import SortableColumn from "./sortable-column";
const TopicCell = <template>
<SortableColumn
@order="default"
@category={{@category}}
@activeOrder={{@activeOrder}}
@changeSort={{@changeSort}}
@ascending={{@ascending}}
@name={{@name}}
@bulkSelectEnabled={{@bulkSelectEnabled}}
@showBulkToggle={{@showBulkToggle}}
@canBulkSelect={{@canBulkSelect}}
@canDoBulkActions={{@canDoBulkActions}}
@showTopicsAndRepliesToggle={{@showTopicsAndRepliesToggle}}
@newListSubset={{@newListSubset}}
@newRepliesCount={{@newRepliesCount}}
@newTopicsCount={{@newTopicsCount}}
@bulkSelectHelper={{@bulkSelectHelper}}
@changeNewListSubset={{@changeNewListSubset}}
/>
</template>;
export default TopicCell;

View File

@ -0,0 +1,15 @@
import SortableColumn from "./sortable-column";
const ViewsCell = <template>
<SortableColumn
@sortable={{@sortable}}
@number="true"
@order="views"
@activeOrder={{@activeOrder}}
@changeSort={{@changeSort}}
@ascending={{@ascending}}
@name="views"
/>
</template>;
export default ViewsCell;

View File

@ -6,13 +6,9 @@ import didInsert from "@ember/render-modifiers/modifiers/did-insert";
import { next } from "@ember/runloop"; import { next } from "@ember/runloop";
import { service } from "@ember/service"; import { service } from "@ember/service";
import { modifier } from "ember-modifier"; import { modifier } from "ember-modifier";
import { eq, gt } from "truth-helpers"; import { eq } from "truth-helpers";
import PluginOutlet from "discourse/components/plugin-outlet"; import PluginOutlet from "discourse/components/plugin-outlet";
import ActivityColumn from "discourse/components/topic-list/activity-column";
import PostCountOrBadges from "discourse/components/topic-list/post-count-or-badges"; import PostCountOrBadges from "discourse/components/topic-list/post-count-or-badges";
import PostersColumn from "discourse/components/topic-list/posters-column";
import PostsCountColumn from "discourse/components/topic-list/posts-count-column";
import TopicCell from "discourse/components/topic-list/topic-cell";
import TopicExcerpt from "discourse/components/topic-list/topic-excerpt"; import TopicExcerpt from "discourse/components/topic-list/topic-excerpt";
import TopicLink from "discourse/components/topic-list/topic-link"; import TopicLink from "discourse/components/topic-list/topic-link";
import TopicStatus from "discourse/components/topic-status"; import TopicStatus from "discourse/components/topic-status";
@ -22,14 +18,12 @@ import categoryLink from "discourse/helpers/category-link";
import concatClass from "discourse/helpers/concat-class"; import concatClass from "discourse/helpers/concat-class";
import discourseTags from "discourse/helpers/discourse-tags"; import discourseTags from "discourse/helpers/discourse-tags";
import formatDate from "discourse/helpers/format-date"; import formatDate from "discourse/helpers/format-date";
import number from "discourse/helpers/number";
import topicFeaturedLink from "discourse/helpers/topic-featured-link"; import topicFeaturedLink from "discourse/helpers/topic-featured-link";
import { wantsNewWindow } from "discourse/lib/intercept-click"; import { wantsNewWindow } from "discourse/lib/intercept-click";
import DiscourseURL from "discourse/lib/url"; import DiscourseURL from "discourse/lib/url";
import icon from "discourse-common/helpers/d-icon";
import { i18n } from "discourse-i18n"; import { i18n } from "discourse-i18n";
export default class TopicListItem extends Component { export default class Item extends Component {
@service historyStore; @service historyStore;
@service site; @service site;
@service siteSettings; @service siteSettings;
@ -119,13 +113,11 @@ export default class TopicListItem extends Component {
if (e.target.checked) { if (e.target.checked) {
this.args.selected.addObject(this.args.topic); this.args.selected.addObject(this.args.topic);
if (this.args.lastCheckedElementId && e.shiftKey) { if (this.args.bulkSelectHelper.lastCheckedElementId && e.shiftKey) {
const bulkSelects = Array.from( const bulkSelects = [...document.querySelectorAll("input.bulk-select")];
document.querySelectorAll("input.bulk-select")
);
const from = bulkSelects.indexOf(e.target); const from = bulkSelects.indexOf(e.target);
const to = bulkSelects.findIndex( const to = bulkSelects.findIndex(
(el) => el.id === this.args.lastCheckedElementId (el) => el.id === this.args.bulkSelectHelper.lastCheckedElementId
); );
const start = Math.min(from, to); const start = Math.min(from, to);
const end = Math.max(from, to); const end = Math.max(from, to);
@ -136,10 +128,10 @@ export default class TopicListItem extends Component {
.forEach((checkbox) => checkbox.click()); .forEach((checkbox) => checkbox.click());
} }
this.args.updateLastCheckedElementId(e.target.id); this.args.bulkSelectHelper.lastCheckedElementId = e.target.id;
} else { } else {
this.args.selected.removeObject(this.args.topic); this.args.selected.removeObject(this.args.topic);
this.args.updateLastCheckedElementId(null); this.args.bulkSelectHelper.lastCheckedElementId = null;
} }
} }
@ -223,78 +215,20 @@ export default class TopicListItem extends Component {
@outletArgs={{hash topic=@topic}} @outletArgs={{hash topic=@topic}}
/> />
{{#if this.site.desktopView}} {{#if this.site.desktopView}}
{{! TODO: column DAG "topic-list-before-columns" }} {{#each @columns as |entry|}}
<entry.value.item
{{#if @bulkSelectEnabled}}
<td class="bulk-select topic-list-data">
<label for="bulk-select-{{@topic.id}}">
<input
{{on "click" this.onBulkSelectToggle}}
checked={{this.isSelected}}
type="checkbox"
id="bulk-select-{{@topic.id}}"
class="bulk-select"
/>
</label>
</td>
{{/if}}
<TopicCell
@topic={{@topic}} @topic={{@topic}}
@bulkSelectEnabled={{@bulkSelectEnabled}}
@onBulkSelectToggle={{this.onBulkSelectToggle}}
@isSelected={{this.isSelected}}
@showTopicPostBadges={{@showTopicPostBadges}} @showTopicPostBadges={{@showTopicPostBadges}}
@hideCategory={{@hideCategory}} @hideCategory={{@hideCategory}}
@tagsForUser={{@tagsForUser}} @tagsForUser={{@tagsForUser}}
@expandPinned={{this.expandPinned}} @expandPinned={{this.expandPinned}}
/> />
{{/each}}
<PluginOutlet
@name="topic-list-after-main-link"
@outletArgs={{hash topic=@topic}}
/>
{{#if @showPosters}}
<PostersColumn @posters={{@topic.featuredUsers}} />
{{/if}}
<PostsCountColumn @topic={{@topic}} />
{{#if @showLikes}}
<td class="num likes topic-list-data">
{{#if (gt @topic.like_count 0)}}
<a href={{@topic.summaryUrl}}>
{{number @topic.like_count}}
{{icon "heart"}}
</a>
{{/if}}
</td>
{{/if}}
{{#if @showOpLikes}}
<td class="num likes">
{{#if (gt @topic.op_like_count 0)}}
<a href={{@topic.summaryUrl}}>
{{number @topic.op_like_count}}
{{icon "heart"}}
</a>
{{/if}}
</td>
{{/if}}
<td class={{concatClass "num views topic-list-data" @topic.viewsHeat}}>
<PluginOutlet
@name="topic-list-before-view-count"
@outletArgs={{hash topic=@topic}}
/>
{{number @topic.views numberKey="views_long"}}
</td>
<ActivityColumn @topic={{@topic}} class="num topic-list-data" />
{{! TODO: column DAG "topic-list-after-columns" }}
{{else}} {{else}}
<td class="topic-list-data"> <td class="topic-list-data">
{{! TODO: column DAG "topic-list-before-columns" }}
<div class="pull-left"> <div class="pull-left">
{{#if @bulkSelectEnabled}} {{#if @bulkSelectEnabled}}
<label for="bulk-select-{{@topic.id}}"> <label for="bulk-select-{{@topic.id}}">

View File

@ -5,20 +5,17 @@ import coldAgeClass from "discourse/helpers/cold-age-class";
import concatClass from "discourse/helpers/concat-class"; import concatClass from "discourse/helpers/concat-class";
import formatDate from "discourse/helpers/format-date"; import formatDate from "discourse/helpers/format-date";
const ActivityColumn = <template> const ActivityCell = <template>
<td <td
title={{htmlSafe @topic.bumpedAtTitle}} title={{htmlSafe @topic.bumpedAtTitle}}
class={{concatClass class={{concatClass
"activity" "activity num topic-list-data"
(coldAgeClass @topic.createdAt startDate=@topic.bumpedAt class="") (coldAgeClass @topic.createdAt startDate=@topic.bumpedAt class="")
}} }}
...attributes
> >
<a <a href={{@topic.lastPostUrl}} class="post-activity">
href={{@topic.lastPostUrl}} {{~! no whitespace ~}}
class="post-activity" <PluginOutlet
>{{! no whitespace
}}<PluginOutlet
@name="topic-list-before-relative-date" @name="topic-list-before-relative-date"
@outletArgs={{hash topic=@topic}} @outletArgs={{hash topic=@topic}}
/> />
@ -26,4 +23,5 @@ const ActivityColumn = <template>
</a> </a>
</td> </td>
</template>; </template>;
export default ActivityColumn;
export default ActivityCell;

View File

@ -0,0 +1,17 @@
import { on } from "@ember/modifier";
const BulkSelectCell = <template>
<td class="bulk-select topic-list-data">
<label for="bulk-select-{{@topic.id}}">
<input
{{on "click" @onBulkSelectToggle}}
checked={{@isSelected}}
type="checkbox"
id="bulk-select-{{@topic.id}}"
class="bulk-select"
/>
</label>
</td>
</template>;
export default BulkSelectCell;

View File

@ -0,0 +1,16 @@
import { gt } from "truth-helpers";
import number from "discourse/helpers/number";
import icon from "discourse-common/helpers/d-icon";
const LikesCell = <template>
<td class="num likes topic-list-data">
{{#if (gt @topic.like_count 0)}}
<a href={{@topic.summaryUrl}}>
{{number @topic.like_count}}
{{icon "heart"}}
</a>
{{/if}}
</td>
</template>;
export default LikesCell;

View File

@ -0,0 +1,16 @@
import { gt } from "truth-helpers";
import number from "discourse/helpers/number";
import icon from "discourse-common/helpers/d-icon";
const OpLikesCell = <template>
<td class="num likes">
{{#if (gt @topic.op_like_count 0)}}
<a href={{@topic.summaryUrl}}>
{{number @topic.op_like_count}}
{{icon "heart"}}
</a>
{{/if}}
</td>
</template>;
export default OpLikesCell;

View File

@ -1,8 +1,8 @@
import avatar from "discourse/helpers/avatar"; import avatar from "discourse/helpers/avatar";
const PostersColumn = <template> const PostersCell = <template>
<td class="posters topic-list-data"> <td class="posters topic-list-data">
{{#each @posters as |poster|}} {{#each @topic.featuredUsers as |poster|}}
{{#if poster.moreCount}} {{#if poster.moreCount}}
<a class="posters-more-count">{{poster.moreCount}}</a> <a class="posters-more-count">{{poster.moreCount}}</a>
{{else}} {{else}}
@ -22,4 +22,4 @@ const PostersColumn = <template>
</td> </td>
</template>; </template>;
export default PostersColumn; export default PostersCell;

View File

@ -6,7 +6,7 @@ import element from "discourse/helpers/element";
import number from "discourse/helpers/number"; import number from "discourse/helpers/number";
import I18n from "discourse-i18n"; import I18n from "discourse-i18n";
export default class PostsCountColumn extends Component { export default class RepliesCell extends Component {
@service siteSettings; @service siteSettings;
get ratio() { get ratio() {

View File

@ -0,0 +1,16 @@
import { hash } from "@ember/helper";
import PluginOutlet from "discourse/components/plugin-outlet";
import concatClass from "discourse/helpers/concat-class";
import number from "discourse/helpers/number";
const ViewsCell = <template>
<td class={{concatClass "num views topic-list-data" @topic.viewsHeat}}>
<PluginOutlet
@name="topic-list-before-view-count"
@outletArgs={{hash topic=@topic}}
/>
{{number @topic.views numberKey="views_long"}}
</td>
</template>;
export default ViewsCell;

View File

@ -1,7 +1,7 @@
import Component from "@glimmer/component"; import Component from "@glimmer/component";
import { concat, hash } from "@ember/helper"; import { concat, hash } from "@ember/helper";
import PluginOutlet from "discourse/components/plugin-outlet"; import PluginOutlet from "discourse/components/plugin-outlet";
import PostsCountColumn from "discourse/components/topic-list/posts-count-column"; import ItemRepliesCell from "discourse/components/topic-list/item/replies-cell";
import TopicPostBadges from "discourse/components/topic-post-badges"; import TopicPostBadges from "discourse/components/topic-post-badges";
import TopicStatus from "discourse/components/topic-status"; import TopicStatus from "discourse/components/topic-status";
import UserAvatarFlair from "discourse/components/user-avatar-flair"; import UserAvatarFlair from "discourse/components/user-avatar-flair";
@ -75,7 +75,7 @@ export default class LatestTopicListItem extends Component {
@outletArgs={{hash topic=@topic}} @outletArgs={{hash topic=@topic}}
/> />
<PostsCountColumn @topic={{@topic}} @tagName="div" /> <ItemRepliesCell @topic={{@topic}} @tagName="div" />
<div class="topic-last-activity"> <div class="topic-last-activity">
<a <a

View File

@ -1,18 +1,109 @@
import Component from "@glimmer/component"; import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking"; import { cached } from "@glimmer/tracking";
import { fn, hash } from "@ember/helper"; import { hash } from "@ember/helper";
import { service } from "@ember/service"; import { service } from "@ember/service";
import { eq, or } from "truth-helpers"; import { eq, or } from "truth-helpers";
import PluginOutlet from "discourse/components/plugin-outlet"; import PluginOutlet from "discourse/components/plugin-outlet";
import TopicListHeader from "discourse/components/topic-list/topic-list-header"; import Header from "discourse/components/topic-list/header";
import TopicListItem from "discourse/components/topic-list/topic-list-item"; import Item from "discourse/components/topic-list/item";
import concatClass from "discourse/helpers/concat-class"; import concatClass from "discourse/helpers/concat-class";
import DAG from "discourse/lib/dag";
import { applyValueTransformer } from "discourse/lib/transformer";
import { i18n } from "discourse-i18n"; import { i18n } from "discourse-i18n";
import HeaderActivityCell from "./header/activity-cell";
import HeaderBulkSelectCell from "./header/bulk-select-cell";
import HeaderLikesCell from "./header/likes-cell";
import HeaderOpLikesCell from "./header/op-likes-cell";
import HeaderPostersCell from "./header/posters-cell";
import HeaderRepliesCell from "./header/replies-cell";
import HeaderTopicCell from "./header/topic-cell";
import HeaderViewsCell from "./header/views-cell";
import ItemActivityCell from "./item/activity-cell";
import ItemBulkSelectCell from "./item/bulk-select-cell";
import ItemLikesCell from "./item/likes-cell";
import ItemOpLikesCell from "./item/op-likes-cell";
import ItemPostersCell from "./item/posters-cell";
import ItemRepliesCell from "./item/replies-cell";
import ItemTopicCell from "./item/topic-cell";
import ItemViewsCell from "./item/views-cell";
export default class TopicList extends Component { export default class TopicList extends Component {
@service currentUser; @service currentUser;
@service topicTrackingState;
@tracked lastCheckedElementId; @cached
get columns() {
const defaultColumns = new DAG({
// Allow customizations to replace just a header cell or just an item cell
onReplaceItem(_, newValue, oldValue) {
newValue.header ??= oldValue.header;
newValue.item ??= oldValue.item;
},
});
if (this.bulkSelectEnabled) {
defaultColumns.add("bulk-select", {
header: HeaderBulkSelectCell,
item: ItemBulkSelectCell,
});
}
defaultColumns.add("topic", {
header: HeaderTopicCell,
item: ItemTopicCell,
});
if (this.args.showPosters) {
defaultColumns.add("posters", {
header: HeaderPostersCell,
item: ItemPostersCell,
});
}
defaultColumns.add("replies", {
header: HeaderRepliesCell,
item: ItemRepliesCell,
});
if (this.args.order === "likes") {
defaultColumns.add("likes", {
header: HeaderLikesCell,
item: ItemLikesCell,
});
} else if (this.args.order === "op_likes") {
defaultColumns.add("op-likes", {
header: HeaderOpLikesCell,
item: ItemOpLikesCell,
});
}
defaultColumns.add("views", {
header: HeaderViewsCell,
item: ItemViewsCell,
});
defaultColumns.add("activity", {
header: HeaderActivityCell,
item: ItemActivityCell,
});
const self = this;
const context = {
get category() {
return self.topicTrackingState.get("filterCategory");
},
get filter() {
return self.topicTrackingState.get("filter");
},
};
return applyValueTransformer(
"topic-list-columns",
defaultColumns,
context
).resolve();
}
get selected() { get selected() {
return this.args.bulkSelectHelper?.selected; return this.args.bulkSelectHelper?.selected;
@ -34,12 +125,8 @@ export default class TopicList extends Component {
return !!this.args.changeSort; return !!this.args.changeSort;
} }
get showLikes() { get showTopicPostBadges() {
return this.args.order === "likes"; return this.args.showTopicPostBadges ?? true;
}
get showOpLikes() {
return this.args.order === "op_likes";
} }
get lastVisitedTopic() { get lastVisitedTopic() {
@ -83,10 +170,6 @@ export default class TopicList extends Component {
return lastVisitedTopic; return lastVisitedTopic;
} }
get showTopicPostBadges() {
return this.args.showTopicPostBadges ?? true;
}
<template> <template>
{{! template-lint-disable table-groups }} {{! template-lint-disable table-groups }}
<table <table
@ -97,21 +180,19 @@ export default class TopicList extends Component {
> >
<caption class="sr-only">{{i18n "sr_topic_list_caption"}}</caption> <caption class="sr-only">{{i18n "sr_topic_list_caption"}}</caption>
<thead class="topic-list-header"> <thead class="topic-list-header">
<TopicListHeader <Header
@columns={{this.columns}}
@canBulkSelect={{@canBulkSelect}} @canBulkSelect={{@canBulkSelect}}
@toggleInTitle={{this.toggleInTitle}} @toggleInTitle={{this.toggleInTitle}}
@category={{@category}} @category={{@category}}
@hideCategory={{@hideCategory}} @hideCategory={{@hideCategory}}
@showPosters={{@showPosters}}
@showLikes={{this.showLikes}}
@showOpLikes={{this.showOpLikes}}
@order={{@order}} @order={{@order}}
@changeSort={{@changeSort}} @changeSort={{@changeSort}}
@ascending={{@ascending}} @ascending={{@ascending}}
@sortable={{this.sortable}} @sortable={{this.sortable}}
@listTitle={{or @listTitle "topic.title"}} @listTitle={{or @listTitle "topic.title"}}
@bulkSelectEnabled={{this.bulkSelectEnabled}}
@bulkSelectHelper={{@bulkSelectHelper}} @bulkSelectHelper={{@bulkSelectHelper}}
@bulkSelectEnabled={{this.bulkSelectEnabled}}
@canDoBulkActions={{this.canDoBulkActions}} @canDoBulkActions={{this.canDoBulkActions}}
@showTopicsAndRepliesToggle={{@showTopicsAndRepliesToggle}} @showTopicsAndRepliesToggle={{@showTopicsAndRepliesToggle}}
@newListSubset={{@newListSubset}} @newListSubset={{@newListSubset}}
@ -135,20 +216,17 @@ export default class TopicList extends Component {
<tbody class="topic-list-body"> <tbody class="topic-list-body">
{{#each @topics as |topic index|}} {{#each @topics as |topic index|}}
<TopicListItem <Item
@columns={{this.columns}}
@topic={{topic}} @topic={{topic}}
@bulkSelectHelper={{@bulkSelectHelper}}
@bulkSelectEnabled={{this.bulkSelectEnabled}} @bulkSelectEnabled={{this.bulkSelectEnabled}}
@showTopicPostBadges={{this.showTopicPostBadges}} @showTopicPostBadges={{this.showTopicPostBadges}}
@hideCategory={{@hideCategory}} @hideCategory={{@hideCategory}}
@showPosters={{@showPosters}}
@showLikes={{this.showLikes}}
@showOpLikes={{this.showOpLikes}}
@expandGloballyPinned={{@expandGloballyPinned}} @expandGloballyPinned={{@expandGloballyPinned}}
@expandAllPinned={{@expandAllPinned}} @expandAllPinned={{@expandAllPinned}}
@lastVisitedTopic={{this.lastVisitedTopic}} @lastVisitedTopic={{this.lastVisitedTopic}}
@selected={{this.selected}} @selected={{this.selected}}
@lastCheckedElementId={{this.lastCheckedElementId}}
@updateLastCheckedElementId={{fn (mut this.lastCheckedElementId)}}
@tagsForUser={{@tagsForUser}} @tagsForUser={{@tagsForUser}}
@focusLastVisitedTopic={{@focusLastVisitedTopic}} @focusLastVisitedTopic={{@focusLastVisitedTopic}}
@index={{index}} @index={{index}}

View File

@ -1,5 +1,5 @@
import { and } from "truth-helpers"; import { and } from "truth-helpers";
import PostsCountColumn from "discourse/components/topic-list/posts-count-column"; import ItemRepliesCell from "discourse/components/topic-list/item/replies-cell";
import TopicPostBadges from "discourse/components/topic-post-badges"; import TopicPostBadges from "discourse/components/topic-post-badges";
const PostCountOrBadges = <template> const PostCountOrBadges = <template>
@ -10,7 +10,7 @@ const PostCountOrBadges = <template>
@url={{@topic.lastUnreadUrl}} @url={{@topic.lastUnreadUrl}}
/> />
{{else}} {{else}}
<PostsCountColumn @topic={{@topic}} @tagName="div" /> <ItemRepliesCell @topic={{@topic}} @tagName="div" />
{{/if}} {{/if}}
</template>; </template>;

View File

@ -1,116 +0,0 @@
import { on } from "@ember/modifier";
import PluginOutlet from "discourse/components/plugin-outlet";
import TopicListHeaderColumn from "discourse/components/topic-list/topic-list-header-column";
import icon from "discourse-common/helpers/d-icon";
import { i18n } from "discourse-i18n";
const TopicListHeader = <template>
<tr>
<PluginOutlet @name="topic-list-header-before" />
{{#if @bulkSelectEnabled}}
<th class="bulk-select topic-list-data">
{{#if @canBulkSelect}}
<button
{{on "click" @bulkSelectHelper.toggleBulkSelect}}
title={{i18n "topics.bulk.toggle"}}
class="btn-flat bulk-select"
>
{{icon "list-check"}}
</button>
{{/if}}
</th>
{{/if}}
<TopicListHeaderColumn
@order="default"
@category={{@category}}
@activeOrder={{@order}}
@changeSort={{@changeSort}}
@ascending={{@ascending}}
@name={{@listTitle}}
@bulkSelectEnabled={{@bulkSelectEnabled}}
@showBulkToggle={{@toggleInTitle}}
@canBulkSelect={{@canBulkSelect}}
@canDoBulkActions={{@canDoBulkActions}}
@showTopicsAndRepliesToggle={{@showTopicsAndRepliesToggle}}
@newListSubset={{@newListSubset}}
@newRepliesCount={{@newRepliesCount}}
@newTopicsCount={{@newTopicsCount}}
@bulkSelectHelper={{@bulkSelectHelper}}
@changeNewListSubset={{@changeNewListSubset}}
/>
<PluginOutlet @name="topic-list-header-after-main-link" />
{{#if @showPosters}}
<TopicListHeaderColumn
@order="posters"
@activeOrder={{@order}}
@changeSort={{@changeSort}}
@ascending={{@ascending}}
@name="posters"
@screenreaderOnly={{true}}
aria-label={{i18n "category.sort_options.posters"}}
/>
{{/if}}
<TopicListHeaderColumn
@sortable={{@sortable}}
@number="true"
@order="posts"
@activeOrder={{@order}}
@changeSort={{@changeSort}}
@ascending={{@ascending}}
@name="replies"
/>
{{#if @showLikes}}
<TopicListHeaderColumn
@sortable={{@sortable}}
@number="true"
@order="likes"
@activeOrder={{@order}}
@changeSort={{@changeSort}}
@ascending={{@ascending}}
@name="likes"
/>
{{/if}}
{{#if @showOpLikes}}
<TopicListHeaderColumn
@sortable={{@sortable}}
@number="true"
@order="op_likes"
@activeOrder={{@order}}
@changeSort={{@changeSort}}
@ascending={{@ascending}}
@name="likes"
/>
{{/if}}
<TopicListHeaderColumn
@sortable={{@sortable}}
@number="true"
@order="views"
@activeOrder={{@order}}
@changeSort={{@changeSort}}
@ascending={{@ascending}}
@name="views"
/>
<TopicListHeaderColumn
@sortable={{@sortable}}
@number="true"
@order="activity"
@activeOrder={{@order}}
@changeSort={{@changeSort}}
@ascending={{@ascending}}
@name="activity"
/>
<PluginOutlet @name="topic-list-header-after" />
</tr>
</template>;
export default TopicListHeader;

View File

@ -1,10 +1,10 @@
import { tracked } from "@glimmer/tracking"; import { tracked } from "@glimmer/tracking";
import { action } from "@ember/object";
import { getOwner, setOwner } from "@ember/owner"; import { getOwner, setOwner } from "@ember/owner";
import { service } from "@ember/service"; import { service } from "@ember/service";
import { TrackedArray } from "@ember-compat/tracked-built-ins"; import { TrackedArray } from "@ember-compat/tracked-built-ins";
import { NotificationLevels } from "discourse/lib/notification-levels"; import { NotificationLevels } from "discourse/lib/notification-levels";
import Topic from "discourse/models/topic"; import Topic from "discourse/models/topic";
import { bind } from "discourse-common/utils/decorators";
export default class BulkSelectHelper { export default class BulkSelectHelper {
@service router; @service router;
@ -15,6 +15,7 @@ export default class BulkSelectHelper {
@tracked bulkSelectEnabled = false; @tracked bulkSelectEnabled = false;
@tracked autoAddTopicsToBulkSelect = false; @tracked autoAddTopicsToBulkSelect = false;
@tracked autoAddBookmarksToBulkSelect = false; @tracked autoAddBookmarksToBulkSelect = false;
@tracked lastCheckedElementId = null;
selected = new TrackedArray(); selected = new TrackedArray();
@ -24,6 +25,7 @@ export default class BulkSelectHelper {
clear() { clear() {
this.selected.length = 0; this.selected.length = 0;
this.lastCheckedElementId = null;
} }
addTopics(topics) { addTopics(topics) {
@ -34,8 +36,9 @@ export default class BulkSelectHelper {
return this.selected.mapBy("category_id").uniq(); return this.selected.mapBy("category_id").uniq();
} }
@bind @action
toggleBulkSelect() { toggleBulkSelect(event) {
event?.preventDefault();
this.bulkSelectEnabled = !this.bulkSelectEnabled; this.bulkSelectEnabled = !this.bulkSelectEnabled;
this.clear(); this.clear();
} }

View File

@ -1,10 +1,7 @@
import DAGMap from "dag-map"; import DAGMap from "dag-map";
import { makeArray } from "discourse-common/lib/helpers";
import { bind } from "discourse-common/utils/decorators"; import { bind } from "discourse-common/utils/decorators";
function ensureArray(val) {
return Array.isArray(val) ? val : [val];
}
export default class DAG { export default class DAG {
/** /**
* Creates a new DAG instance from an iterable of entries. * Creates a new DAG instance from an iterable of entries.
@ -75,10 +72,10 @@ export default class DAG {
*/ */
#defaultPositionForKey(key) { #defaultPositionForKey(key) {
const pos = { ...this.#defaultPosition }; const pos = { ...this.#defaultPosition };
if (ensureArray(pos.before).includes(key)) { if (makeArray(pos.before).includes(key)) {
delete pos.before; delete pos.before;
} }
if (ensureArray(pos.after).includes(key)) { if (makeArray(pos.after).includes(key)) {
delete pos.after; delete pos.after;
} }
return pos; return pos;

View File

@ -15,4 +15,5 @@ export const VALUE_TRANSFORMERS = Object.freeze([
"more-topics-tabs", "more-topics-tabs",
"post-menu-buttons", "post-menu-buttons",
"small-user-attrs", "small-user-attrs",
"topic-list-columns",
]); ]);