DEV: replace transformed-post POJO with topic model in topic-map components (#26629)

* DEV: replace postAttrs dependencies in topic-map component by passing in topicDetails and postStream to topic-map to ensure state changes are passed properly down to child components
This commit is contained in:
Kelv 2024-04-18 10:04:38 +08:00 committed by GitHub
parent c5dd50aa02
commit edbd44e737
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 145 additions and 100 deletions

View File

@ -1,9 +1,9 @@
<div class="summary-box__container">
{{#if @postAttrs.hasTopRepliesSummary}}
{{#if this.topRepliesSummaryEnabled}}
<p>{{html-safe this.topRepliesSummaryInfo}}</p>
{{/if}}
<div class="summarization-buttons">
{{#if @postAttrs.summarizable}}
{{#if @topic.summarizable}}
{{#if this.summary.showSummaryBox}}
<DButton
@action={{@collapseSummary}}
@ -24,13 +24,9 @@
{{/if}}
{{/if}}
{{#if @postAttrs.hasTopRepliesSummary}}
{{#if this.topRepliesSummaryEnabled}}
<DButton
@action={{if
@postAttrs.topicSummaryEnabled
@cancelFilter
@showTopReplies
}}
@action={{if @postStream.summary @cancelFilter @showTopReplies}}
@translatedTitle={{this.topRepliesTitle}}
@translatedLabel={{this.topRepliesLabel}}
@icon={{this.topRepliesIcon}}

View File

@ -8,7 +8,7 @@ export default class SummaryBox extends Component {
@service siteSettings;
get summary() {
return this.args.postAttrs.summary;
return this.args.postStream.topicSummary;
}
get generateSummaryTitle() {
@ -27,7 +27,7 @@ export default class SummaryBox extends Component {
let outdatedText = I18n.t("summary.outdated");
if (
!this.args.postAttrs.hasTopRepliesSummary &&
!this.topRepliesSummaryEnabled &&
this.summary.newPostsSinceSummary > 0
) {
outdatedText += " ";
@ -40,29 +40,29 @@ export default class SummaryBox extends Component {
}
get topRepliesSummaryEnabled() {
return this.args.postAttrs.topicSummaryEnabled;
return this.args.topic.has_summary;
}
get topRepliesSummaryInfo() {
if (this.args.postAttrs.topicSummaryEnabled) {
if (this.topRepliesSummaryEnabled) {
return I18n.t("summary.enabled_description");
}
const wordCount = this.args.postAttrs.topicWordCount;
const wordCount = this.args.topic.word_count;
if (wordCount && this.siteSettings.read_time_word_count > 0) {
const readingTime = Math.ceil(
Math.max(
wordCount / this.siteSettings.read_time_word_count,
(this.args.postAttrs.topicPostsCount * MIN_POST_READ_TIME) / 60
(this.args.topic.posts_count * MIN_POST_READ_TIME) / 60
)
);
return I18n.messageFormat("summary.description_time_MF", {
replyCount: this.args.postAttrs.topicReplyCount,
replyCount: this.args.topic.replyCount,
readingTime,
});
}
return I18n.t("summary.description", {
count: this.args.postAttrs.topicReplyCount,
count: this.args.topic.replyCount,
});
}

View File

@ -9,7 +9,11 @@ import concatClass from "discourse/helpers/concat-class";
import or from "truth-helpers/helpers/or";
export default class TopicMap extends Component {
@tracked collapsed = !this.args.postAttrs.hasTopRepliesSummary;
@tracked collapsed = !this.args.model.has_summary;
get userFilters() {
return this.args.postStream.userFilters || [];
}
@action
toggleMap() {
@ -19,9 +23,11 @@ export default class TopicMap extends Component {
<template>
<section class={{concatClass "map" (if this.collapsed "map-collapsed")}}>
<TopicMapSummary
@postAttrs={{@postAttrs}}
@topic={{@model}}
@topicDetails={{@topicDetails}}
@toggleMap={{this.toggleMap}}
@collapsed={{this.collapsed}}
@userFilters={{this.userFilters}}
/>
</section>
{{#unless this.collapsed}}
@ -29,13 +35,17 @@ export default class TopicMap extends Component {
class="topic-map-expanded"
id="topic-map-expanded__aria-controls"
>
<TopicMapExpanded @postAttrs={{@postAttrs}} />
<TopicMapExpanded
@topicDetails={{@topicDetails}}
@userFilters={{this.userFilters}}
/>
</section>
{{/unless}}
{{#if (or @postAttrs.hasTopRepliesSummary @postAttrs.summarizable)}}
{{#if (or @model.has_summary @model.summarizable)}}
<section class="information toggle-summary">
<SummaryBox
@postAttrs={{@postAttrs}}
@topic={{@model}}
@postStream={{@postStream}}
@cancelFilter={{@cancelFilter}}
@showTopReplies={{@showTopReplies}}
@collapseSummary={{@collapseSummary}}
@ -43,10 +53,10 @@ export default class TopicMap extends Component {
/>
</section>
{{/if}}
{{#if @postAttrs.showPMMap}}
{{#if @showPMMap}}
<section class="information private-message-map">
<PrivateMessageMap
@postAttrs={{@postAttrs}}
@topicDetails={{@topicDetails}}
@showInvite={{@showInvite}}
@removeAllowedGroup={{@removeAllowedGroup}}
@removeAllowedUser={{@removeAllowedUser}}

View File

@ -17,19 +17,19 @@ export default class PrivateMessageMap extends Component {
get participantsClasses() {
return !this.isEditing &&
this.site.mobileView &&
this.args.postAttrs.allowedGroups.length > 4
this.args.topicDetails.allowed_groups.length > 4
? "participants hide-names"
: "participants";
}
get canInvite() {
return this.args.postAttrs.canInvite;
return this.args.topicDetails.can_invite_to;
}
get canRemove() {
return (
this.args.postAttrs.canRemoveAllowedUsers ||
this.args.postAttrs.canRemoveSelfId
this.args.topicDetails.can_remove_allowed_users ||
this.args.topicDetails.can_remove_self_id
);
}
@ -58,20 +58,20 @@ export default class PrivateMessageMap extends Component {
<template>
<div class={{this.participantsClasses}}>
{{#each @postAttrs.allowedGroups as |group|}}
{{#each @topicDetails.allowed_groups as |group|}}
<PmMapUserGroup
@model={{group}}
@isEditing={{this.isEditing}}
@canRemoveAllowedUsers={{@postAttrs.canRemoveAllowedUsers}}
@canRemoveAllowedUsers={{@topicDetails.can_remove_allowed_users}}
@removeAllowedGroup={{@removeAllowedGroup}}
/>
{{/each}}
{{#each @postAttrs.allowedUsers as |user|}}
{{#each @topicDetails.allowed_users as |user|}}
<PmMapUser
@model={{user}}
@isEditing={{this.isEditing}}
@canRemoveAllowedUsers={{@postAttrs.canRemoveAllowedUsers}}
@canRemoveSelfId={{@postAttrs.canRemoveSelfId}}
@canRemoveAllowedUsers={{@topicDetails.can_remove_allowed_users}}
@canRemoveSelfId={{@topicDetails.can_remove_self_id}}
@removeAllowedUser={{@removeAllowedUser}}
/>
{{/each}}

View File

@ -14,6 +14,14 @@ const TRUNCATED_LINKS_LIMIT = 5;
export default class TopicMapExpanded extends Component {
@tracked allLinksShown = false;
get topicLinks() {
return this.args.topicDetails.links;
}
get participants() {
return this.args.topicDetails.participants;
}
@action
showAllLinks() {
this.allLinksShown = true;
@ -21,21 +29,21 @@ export default class TopicMapExpanded extends Component {
get linksToShow() {
return this.allLinksShown
? this.args.postAttrs.topicLinks
: this.args.postAttrs.topicLinks.slice(0, TRUNCATED_LINKS_LIMIT);
? this.topicLinks
: this.topicLinks.slice(0, TRUNCATED_LINKS_LIMIT);
}
<template>
{{#if @postAttrs.participants}}
{{#if this.participants}}
<section class="avatars">
<TopicParticipants
@title={{i18n "topic_map.participants_title"}}
@userFilters={{@postAttrs.userFilters}}
@participants={{@postAttrs.participants}}
@userFilters={{@userFilters}}
@participants={{this.participants}}
/>
</section>
{{/if}}
{{#if @postAttrs.topicLinks}}
{{#if this.topicLinks}}
<section class="links">
<h3>{{i18n "topic_map.links_title"}}</h3>
<table class="topic-links">
@ -66,7 +74,7 @@ export default class TopicMapExpanded extends Component {
{{#if
(and
(not this.allLinksShown)
(lt TRUNCATED_LINKS_LIMIT @postAttrs.topicLinks.length)
(lt TRUNCATED_LINKS_LIMIT this.topicLinks.length)
)
}}
<div class="link-summary">

View File

@ -10,6 +10,18 @@ import i18n from "discourse-common/helpers/i18n";
import { avatarImg } from "discourse-common/lib/avatar-utils";
export default class TopicMapSummary extends Component {
get linksCount() {
return this.args.topicDetails.links?.length ?? 0;
}
get createdByUsername() {
return this.args.topicDetails.created_by?.username;
}
get lastPosterUsername() {
return this.args.topicDetails.last_poster?.username;
}
get toggleMapButton() {
return {
title: this.args.collapsed
@ -25,20 +37,20 @@ export default class TopicMapSummary extends Component {
get shouldShowParticipants() {
return (
this.args.collapsed &&
this.args.postAttrs.topicPostsCount > 2 &&
this.args.postAttrs.participants &&
this.args.postAttrs.participants.length > 0
this.args.topic.posts_count > 2 &&
this.args.topicDetails.participants &&
this.args.topicDetails.participants.length > 0
);
}
get createdByAvatar() {
return htmlSafe(
avatarImg({
avatarTemplate: this.args.postAttrs.createdByAvatarTemplate,
avatarTemplate: this.args.topicDetails.created_by?.avatar_template,
size: "tiny",
title:
this.args.postAttrs.createdByName ||
this.args.postAttrs.createdByUsername,
this.args.topicDetails.created_by?.name ||
this.args.topicDetails.created_by?.username,
})
);
}
@ -46,11 +58,11 @@ export default class TopicMapSummary extends Component {
get lastPostAvatar() {
return htmlSafe(
avatarImg({
avatarTemplate: this.args.postAttrs.lastPostAvatarTemplate,
avatarTemplate: this.args.topicDetails.last_poster?.avatar_template,
size: "tiny",
title:
this.args.postAttrs.lastPostName ||
this.args.postAttrs.lastPostUsername,
this.args.topicDetails.last_poster?.name ||
this.args.topicDetails.last_poster?.username,
})
);
}
@ -72,71 +84,67 @@ export default class TopicMapSummary extends Component {
<div class="topic-map-post created-at">
<a
class="trigger-user-card"
data-user-card={{@postAttrs.createdByUsername}}
title={{@postAttrs.createdByUsername}}
data-user-card={{this.createdByUsername}}
title={{this.createdByUsername}}
aria-hidden="true"
/>
{{this.createdByAvatar}}
<RelativeDate @date={{@postAttrs.topicCreatedAt}} />
<RelativeDate @date={{@topic.created_at}} />
</div>
</li>
<li class="last-reply">
<a href={{@postAttrs.lastPostUrl}}>
<a href={{@topic.lastPostUrl}}>
<h4 role="presentation">{{i18n "last_reply_lowercase"}}</h4>
<div class="topic-map-post last-reply">
<a
class="trigger-user-card"
data-user-card={{@postAttrs.lastPostUsername}}
title={{@postAttrs.lastPostUsername}}
data-user-card={{this.lastPosterUsername}}
title={{this.lastPosterUsername}}
aria-hidden="true"
/>
{{this.lastPostAvatar}}
<RelativeDate @date={{@postAttrs.lastPostAt}} />
<RelativeDate @date={{@topic.last_posted_at}} />
</div>
</a>
</li>
<li class="replies">
{{number @postAttrs.topicReplyCount noTitle="true"}}
{{number @topic.replyCount noTitle="true"}}
<h4 role="presentation">{{i18n
"replies_lowercase"
count=@postAttrs.topicReplyCount
count=@topic.replyCount
}}</h4>
</li>
<li class="secondary views">
{{number
@postAttrs.topicViews
noTitle="true"
class=@postAttrs.topicViewsHeat
}}
{{number @topic.views noTitle="true" class=@topic.viewsHeat}}
<h4 role="presentation">{{i18n
"views_lowercase"
count=@postAttrs.topicViews
count=@topic.views
}}</h4>
</li>
{{#if (gt @postAttrs.participantCount 0)}}
{{#if (gt @topic.participant_count 0)}}
<li class="secondary users">
{{number @postAttrs.participantCount noTitle="true"}}
{{number @topic.participant_count noTitle="true"}}
<h4 role="presentation">{{i18n
"users_lowercase"
count=@postAttrs.participantCount
count=@topic.participant_count
}}</h4>
</li>
{{/if}}
{{#if (gt @postAttrs.topicLikeCount 0)}}
{{#if (gt @topic.like_count 0)}}
<li class="secondary likes">
{{number @postAttrs.topicLikeCount noTitle="true"}}
{{number @topic.like_count noTitle="true"}}
<h4 role="presentation">{{i18n
"likes_lowercase"
count=@postAttrs.topicLikeCount
count=@topic.like_count
}}</h4>
</li>
{{/if}}
{{#if (gt @postAttrs.topicLinkCount 0)}}
{{#if (gt this.linksCount 0)}}
<li class="secondary links">
{{number @postAttrs.topicLinkCount noTitle="true"}}
{{number this.linksCount noTitle="true"}}
<h4 role="presentation">{{i18n
"links_lowercase"
count=@postAttrs.topicLinkCount
count=this.linksCount
}}</h4>
</li>
{{/if}}
@ -144,8 +152,8 @@ export default class TopicMapSummary extends Component {
{{#if this.shouldShowParticipants}}
<li class="avatars">
<TopicParticipants
@participants={{slice 0 3 @postAttrs.participants}}
@userFilters={{@postAttrs.userFilters}}
@participants={{slice 0 3 @topicDetails.participants}}
@userFilters={{@userFilters}}
/>
</li>
{{/if}}

View File

@ -755,7 +755,10 @@ createWidget("post-body", {
this,
"div.topic-map",
hbs`<TopicMap
@postAttrs={{@data.postAttrs}}
@model={{@data.model}}
@topicDetails={{@data.topicDetails}}
@postStream={{@data.postStream}}
@showPMMap={{@data.showPMMap}}
@cancelFilter={{@data.cancelFilter}}
@showTopReplies={{@data.showTopReplies}}
@collapseSummary={{@data.collapseSummary}}
@ -765,7 +768,10 @@ createWidget("post-body", {
@removeAllowedUser={{@data.removeAllowedUser}}
/>`,
{
postAttrs: attrs,
model: attrs.topic,
topicDetails: attrs.topic.get("details"),
postStream: attrs.topic.postStream,
showPMMap: attrs.showPMMap,
cancelFilter: () => this.sendWidgetAction("cancelFilter"),
showTopReplies: () => this.sendWidgetAction("showTopReplies"),
collapseSummary: () => this.sendWidgetAction("collapseSummary"),

View File

@ -780,10 +780,16 @@ module("Integration | Component | Widget | post", function (hooks) {
});
test("topic map - few posts", async function (assert) {
const store = getOwner(this).lookup("service:store");
const topic = store.createRecord("topic", { id: 123 });
topic.details.set("participants", [
{ username: "eviltrout" },
{ username: "codinghorror" },
]);
this.set("args", {
topic,
showTopicMap: true,
topicPostsCount: 2,
participants: [{ username: "eviltrout" }, { username: "codinghorror" }],
});
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
@ -794,16 +800,19 @@ module("Integration | Component | Widget | post", function (hooks) {
});
test("topic map - participants", async function (assert) {
const store = getOwner(this).lookup("service:store");
const topic = store.createRecord("topic", { id: 123, posts_count: 10 });
topic.postStream.setProperties({ userFilters: ["sam", "codinghorror"] });
topic.details.set("participants", [
{ username: "eviltrout" },
{ username: "codinghorror" },
{ username: "sam" },
{ username: "ZogStrIP" },
]);
this.set("args", {
topic,
showTopicMap: true,
topicPostsCount: 10,
participants: [
{ username: "eviltrout" },
{ username: "codinghorror" },
{ username: "sam" },
{ username: "ZogStrIP" },
],
userFilters: ["sam", "codinghorror"],
});
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
@ -816,17 +825,17 @@ module("Integration | Component | Widget | post", function (hooks) {
});
test("topic map - links", async function (assert) {
this.set("args", {
showTopicMap: true,
topicLinks: [
{ url: "http://link1.example.com", clicks: 0 },
{ url: "http://link2.example.com", clicks: 0 },
{ url: "http://link3.example.com", clicks: 0 },
{ url: "http://link4.example.com", clicks: 0 },
{ url: "http://link5.example.com", clicks: 0 },
{ url: "http://link6.example.com", clicks: 0 },
],
});
const store = getOwner(this).lookup("service:store");
const topic = store.createRecord("topic", { id: 123 });
topic.details.set("links", [
{ url: "http://link1.example.com", clicks: 0 },
{ url: "http://link2.example.com", clicks: 0 },
{ url: "http://link3.example.com", clicks: 0 },
{ url: "http://link4.example.com", clicks: 0 },
{ url: "http://link5.example.com", clicks: 0 },
{ url: "http://link6.example.com", clicks: 0 },
]);
this.set("args", { topic, showTopicMap: true });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
@ -845,7 +854,9 @@ module("Integration | Component | Widget | post", function (hooks) {
});
test("topic map - no summary", async function (assert) {
this.set("args", { showTopicMap: true });
const store = getOwner(this).lookup("service:store");
const topic = store.createRecord("topic", { id: 123 });
this.set("args", { topic, showTopicMap: true });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
@ -853,7 +864,9 @@ module("Integration | Component | Widget | post", function (hooks) {
});
test("topic map - has top replies summary", async function (assert) {
this.set("args", { showTopicMap: true, hasTopRepliesSummary: true });
const store = getOwner(this).lookup("service:store");
const topic = store.createRecord("topic", { id: 123, has_summary: true });
this.set("args", { topic, showTopicMap: true });
this.set("showTopReplies", () => (this.summaryToggled = true));
await render(
@ -867,11 +880,15 @@ module("Integration | Component | Widget | post", function (hooks) {
});
test("pm map", async function (assert) {
const store = getOwner(this).lookup("service:store");
const topic = store.createRecord("topic", { id: 123 });
topic.details.set("allowed_users", [
EmberObject.create({ username: "eviltrout" }),
]);
this.set("args", {
topic,
showTopicMap: true,
showPMMap: true,
allowedGroups: [],
allowedUsers: [EmberObject.create({ username: "eviltrout" })],
});
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);