diff --git a/app/assets/javascripts/discourse/app/components/topic-map/topic-map-summary.gjs b/app/assets/javascripts/discourse/app/components/topic-map/topic-map-summary.gjs
index 38ec0eea1c8..0979302d0d1 100644
--- a/app/assets/javascripts/discourse/app/components/topic-map/topic-map-summary.gjs
+++ b/app/assets/javascripts/discourse/app/components/topic-map/topic-map-summary.gjs
@@ -91,18 +91,11 @@ export default class TopicMapSummary extends Component {
if (this.args.topic.has_summary) {
return false;
}
-
- return (
- [this.hasViews, this.hasLikes, this.hasUsers, this.hasLinks].filter(
- Boolean
- ).length === 1
- );
+ return [this.hasLikes, this.hasUsers, this.hasLinks].every((stat) => !stat);
}
get manyStats() {
- return [this.hasViews, this.hasLikes, this.hasUsers, this.hasLinks].every(
- Boolean
- );
+ return [this.hasLikes, this.hasUsers, this.hasLinks].every(Boolean);
}
get shouldShowViewsChart() {
@@ -127,10 +120,6 @@ export default class TopicMapSummary extends Component {
return !this.allLinksShown && this.linksCount > TRUNCATED_LINKS_LIMIT;
}
- get hasViews() {
- return this.args.topic.views > 1;
- }
-
get hasLikes() {
return (
this.args.topic.like_count > MIN_LIKES_COUNT &&
@@ -409,7 +398,7 @@ export default class TopicMapSummary extends Component {
<:content>
@@ -419,7 +408,7 @@ export default class TopicMapSummary extends Component {
{{#if this.shouldShowParticipants}}
{{/if}}
diff --git a/app/assets/javascripts/discourse/app/controllers/topic.js b/app/assets/javascripts/discourse/app/controllers/topic.js
index 63e965acd58..7f16c7b5577 100644
--- a/app/assets/javascripts/discourse/app/controllers/topic.js
+++ b/app/assets/javascripts/discourse/app/controllers/topic.js
@@ -236,7 +236,11 @@ export default class TopicController extends Controller.extend(
@discourseComputed("model.posts_count", "model.postStream.loadingFilter")
showBottomTopicMap(postsCount, loading) {
- return !loading && postsCount > MIN_POSTS_COUNT;
+ return (
+ this.siteSettings.show_bottom_topic_map &&
+ !loading &&
+ postsCount > MIN_POSTS_COUNT
+ );
}
_removeDeleteOnOwnerReplyBookmarks() {
diff --git a/app/assets/javascripts/discourse/app/lib/transform-post.js b/app/assets/javascripts/discourse/app/lib/transform-post.js
index 8c96353a63e..1cb2e483f83 100644
--- a/app/assets/javascripts/discourse/app/lib/transform-post.js
+++ b/app/assets/javascripts/discourse/app/lib/transform-post.js
@@ -169,64 +169,6 @@ export default function transformPost(
postAtts.requestedGroupName = topic.requested_group_name;
}
- const showPMMap =
- topic.archetype === "private_message" && post.post_number === 1;
- if (showPMMap) {
- postAtts.showPMMap = true;
- postAtts.allowedGroups = details.allowed_groups;
- postAtts.allowedUsers = details.allowed_users;
- postAtts.canRemoveAllowedUsers = details.can_remove_allowed_users;
- postAtts.canRemoveSelfId = details.can_remove_self_id;
- postAtts.canInvite = details.can_invite_to;
- }
-
- const showTopicMap =
- (_additionalAttributes.includes("topicMap") && post.post_number === 1) ||
- showPMMap ||
- (post.post_number === 1 &&
- topic.archetype === "regular" &&
- topic.posts_count > 1);
- if (showTopicMap) {
- postAtts.showTopicMap = true;
- postAtts.topicCreatedAt = topic.created_at;
- postAtts.createdByUsername = createdBy.username;
- postAtts.createdByAvatarTemplate = createdBy.avatar_template;
- postAtts.createdByName = createdBy.name;
-
- postAtts.lastPostUrl = topic.get("lastPostUrl");
- if (details.last_poster) {
- postAtts.lastPostUsername = details.last_poster.username;
- postAtts.lastPostAvatarTemplate = details.last_poster.avatar_template;
- postAtts.lastPostName = details.last_poster.name;
- }
- postAtts.lastPostAt = topic.last_posted_at;
-
- postAtts.topicReplyCount = topic.get("replyCount");
- postAtts.topicViews = topic.views;
- postAtts.topicViewsHeat = topic.get("viewsHeat");
-
- postAtts.participantCount = topic.participant_count;
- postAtts.topicLikeCount = topic.like_count;
- postAtts.topicLinks = details.links;
- if (postAtts.topicLinks) {
- postAtts.topicLinkLength = details.links.length;
- }
- postAtts.topicPostsCount = topic.posts_count;
-
- postAtts.participants = details.participants;
-
- const postStream = topic.get("postStream");
- postAtts.userFilters = postStream.userFilters;
- postAtts.topicSummaryEnabled = postStream.summary;
- postAtts.topicWordCount = topic.word_count;
- postAtts.hasTopRepliesSummary = topic.has_summary;
- postAtts.summarizable = topic.summarizable;
-
- if (post.post_number === 1) {
- postAtts.summary = postStream.topicSummary;
- }
- }
-
if (postAtts.isDeleted) {
postAtts.deletedByAvatarTemplate = post.get(
"postDeletedBy.avatar_template"
diff --git a/app/assets/javascripts/discourse/app/widgets/post.js b/app/assets/javascripts/discourse/app/widgets/post.js
index 443133b72ee..aa8ee9a5834 100644
--- a/app/assets/javascripts/discourse/app/widgets/post.js
+++ b/app/assets/javascripts/discourse/app/widgets/post.js
@@ -831,7 +831,7 @@ createWidget("post-article", {
])
);
- if (attrs.showTopicMap) {
+ if (this.shouldShowTopicMap(attrs)) {
rows.push(this.buildTopicMap(attrs));
}
@@ -900,6 +900,22 @@ createWidget("post-article", {
}
},
+ shouldShowTopicMap(attrs) {
+ if (attrs.post_number !== 1) {
+ return false;
+ }
+ const isPM = attrs.topic.archetype === "private_message";
+ const isRegular = attrs.topic.archetype === "regular";
+ const showWithoutReplies =
+ this.siteSettings.show_topic_map_in_topics_without_replies;
+
+ return (
+ attrs.topicMap ||
+ isPM ||
+ (isRegular && (attrs.topic.posts_count > 1 || showWithoutReplies))
+ );
+ },
+
buildTopicMap(attrs) {
return new RenderGlimmer(
this,
@@ -917,7 +933,7 @@ createWidget("post-article", {
model: attrs.topic,
topicDetails: attrs.topic.get("details"),
postStream: attrs.topic.postStream,
- showPMMap: attrs.showPMMap,
+ showPMMap: attrs.topic.archetype === "private_message",
showInvite: () => this.sendWidgetAction("showInvite"),
removeAllowedGroup: (group) =>
this.sendWidgetAction("removeAllowedGroup", group),
diff --git a/app/assets/javascripts/discourse/tests/integration/components/widgets/post-test.js b/app/assets/javascripts/discourse/tests/integration/components/widgets/post-test.js
index 4ac74c9b48f..13344564b13 100644
--- a/app/assets/javascripts/discourse/tests/integration/components/widgets/post-test.js
+++ b/app/assets/javascripts/discourse/tests/integration/components/widgets/post-test.js
@@ -16,7 +16,13 @@ module("Integration | Component | Widget | post", function (hooks) {
setupRenderingTest(hooks);
test("basic elements", async function (assert) {
- this.set("args", { shareUrl: "/example", post_number: 1 });
+ const store = getOwner(this).lookup("service:store");
+ const topic = store.createRecord("topic", {
+ id: 123,
+ archetype: "regular",
+ });
+
+ this.set("args", { shareUrl: "/example", post_number: 1, topic });
await render(hbs``);
@@ -771,12 +777,29 @@ module("Integration | Component | Widget | post", function (hooks) {
assert.strictEqual(count("section.embedded-posts .d-icon-arrow-down"), 1);
});
- test("topic map not shown", async function (assert) {
- this.set("args", { showTopicMap: false });
+ test("shows the topic map when setting the 'topicMap' attribute", async function (assert) {
+ const store = getOwner(this).lookup("service:store");
+ const topic = store.createRecord("topic", { id: 123 });
+ this.set("args", { topic, post_number: 1, topicMap: true });
await render(hbs``);
- assert.dom(".topic-map").doesNotExist();
+ assert.dom(".topic-map").exists();
+ });
+
+ test("shows the topic map when no replies", async function (assert) {
+ this.siteSettings.show_topic_map_in_topics_without_replies = true;
+
+ const store = getOwner(this).lookup("service:store");
+ const topic = store.createRecord("topic", {
+ id: 123,
+ archetype: "regular",
+ });
+ this.set("args", { topic, post_number: 1 });
+
+ await render(hbs``);
+
+ assert.dom(".topic-map").exists();
});
test("topic map - few participants", async function (assert) {
@@ -785,6 +808,7 @@ module("Integration | Component | Widget | post", function (hooks) {
id: 123,
posts_count: 10,
participant_count: 2,
+ archetype: "regular",
});
topic.details.set("participants", [
{ username: "eviltrout" },
@@ -792,7 +816,7 @@ module("Integration | Component | Widget | post", function (hooks) {
]);
this.set("args", {
topic,
- showTopicMap: true,
+ post_number: 1,
});
await render(hbs``);
@@ -806,6 +830,7 @@ module("Integration | Component | Widget | post", function (hooks) {
id: 123,
posts_count: 10,
participant_count: 6,
+ archetype: "regular",
});
topic.postStream.setProperties({ userFilters: ["sam", "codinghorror"] });
topic.details.set("participants", [
@@ -819,7 +844,7 @@ module("Integration | Component | Widget | post", function (hooks) {
this.set("args", {
topic,
- showTopicMap: true,
+ post_number: 1,
});
await render(hbs``);
@@ -833,7 +858,11 @@ module("Integration | Component | Widget | post", function (hooks) {
test("topic map - links", async function (assert) {
const store = getOwner(this).lookup("service:store");
- const topic = store.createRecord("topic", { id: 123 });
+ const topic = store.createRecord("topic", {
+ id: 123,
+ posts_count: 2,
+ archetype: "regular",
+ });
topic.details.set("links", [
{ url: "http://link1.example.com", clicks: 0 },
{ url: "http://link2.example.com", clicks: 0 },
@@ -842,7 +871,7 @@ module("Integration | Component | Widget | post", function (hooks) {
{ url: "http://link5.example.com", clicks: 0 },
{ url: "http://link6.example.com", clicks: 0 },
]);
- this.set("args", { topic, showTopicMap: true });
+ this.set("args", { topic, post_number: 1 });
await render(hbs``);
@@ -857,18 +886,28 @@ module("Integration | Component | Widget | post", function (hooks) {
test("topic map - no top reply summary", async function (assert) {
const store = getOwner(this).lookup("service:store");
- const topic = store.createRecord("topic", { id: 123 });
- this.set("args", { topic, showTopicMap: true });
+ const topic = store.createRecord("topic", {
+ id: 123,
+ archetype: "regular",
+ posts_count: 2,
+ });
+ this.set("args", { topic, post_number: 1 });
await render(hbs``);
+ assert.dom(".topic-map").exists();
assert.dom(".summarization-button .top-replies").doesNotExist();
});
test("topic map - has top replies summary", async function (assert) {
const store = getOwner(this).lookup("service:store");
- const topic = store.createRecord("topic", { id: 123, has_summary: true });
- this.set("args", { topic, showTopicMap: true });
+ const topic = store.createRecord("topic", {
+ id: 123,
+ archetype: "regular",
+ posts_count: 2,
+ has_summary: true,
+ });
+ this.set("args", { topic, post_number: 1 });
await render(hbs``);
@@ -877,14 +916,16 @@ 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 });
+ const topic = store.createRecord("topic", {
+ id: 123,
+ archetype: "private_message",
+ });
topic.details.set("allowed_users", [
EmberObject.create({ username: "eviltrout" }),
]);
this.set("args", {
topic,
- showTopicMap: true,
- showPMMap: true,
+ post_number: 1,
});
await render(hbs``);
diff --git a/app/assets/stylesheets/common/components/topic-map.scss b/app/assets/stylesheets/common/components/topic-map.scss
index 42d5e911f11..a3ee9b1ddf1 100644
--- a/app/assets/stylesheets/common/components/topic-map.scss
+++ b/app/assets/stylesheets/common/components/topic-map.scss
@@ -2,6 +2,10 @@
// topic map under OP
border-top: 1px solid var(--primary-low);
border-bottom: none;
+
+ padding-left: calc(
+ var(--topic-body-width-padding) + var(--topic-avatar-width)
+ );
}
.topic-map.--bottom {
@@ -44,14 +48,13 @@ body:not(.archetype-private_message) {
font-size: var(--font-down-1);
}
- @media screen and (max-width: 500px) {
- padding-left: 0;
+ &.--op,
+ &.--bottom {
+ @media screen and (max-width: 500px) {
+ padding-left: 0;
+ }
}
- padding-left: calc(
- var(--topic-body-width-padding) + var(--topic-avatar-width)
- );
-
.--users-summary {
display: flex;
flex-wrap: wrap;
@@ -158,6 +161,7 @@ body:not(.archetype-private_message) {
.number {
color: var(--tertiary);
+ white-space: nowrap;
}
.topic-map__stat-label {
@@ -310,9 +314,10 @@ body:not(.archetype-private_message) {
// DMenu popups
-.topic-map__likes-content {
+.topic-map__likes-content.fk-d-menu__content {
.fk-d-menu__inner-content,
.d-modal__body {
+ padding-bottom: 0.5em;
ul {
margin: 0;
padding: 0;
@@ -455,14 +460,18 @@ body:not(.archetype-private_message) {
color: var(--primary-medium);
}
- .link-summary .btn {
+ .link-summary {
width: 100%;
- .d-icon {
- color: var(--primary-high);
- }
- .discourse-no-touch & {
- &:hover {
- background: var(--primary-low);
+
+ .btn {
+ width: 100%;
+ .d-icon {
+ color: var(--primary-high);
+ }
+ .discourse-no-touch & {
+ &:hover {
+ background: var(--primary-low);
+ }
}
}
}
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index b7a01da27cb..ed20eb9ce05 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -2664,6 +2664,8 @@ en:
use_email_for_username_and_name_suggestions: "Use the first part of email addresses for username and name suggestions. Note that this makes it easier for the public to guess full user email addresses (because a large proportion of people share common services like `gmail.com`)."
use_name_for_username_suggestions: "Use a user's full name when suggesting usernames."
suggest_weekends_in_date_pickers: "Include weekends (Saturday and Sunday) in date picker suggestions (disable this if you use Discourse only on weekdays, Monday through Friday)."
+ show_bottom_topic_map: "Shows the topic map at the bottom of the topic when it has 10 replies or more."
+ show_topic_map_in_topics_without_replies: "Shows the topic map even if the topic has no replies."
splash_screen: "Displays a temporary loading screen while site assets load"
navigation_menu: "Specify sidebar or header dropdown as the main navigation menu for your site. Sidebar is recommended."
diff --git a/config/site_settings.yml b/config/site_settings.yml
index 472b3cd2e2d..9d20048180b 100644
--- a/config/site_settings.yml
+++ b/config/site_settings.yml
@@ -2976,6 +2976,14 @@ uncategorized:
client: true
default: true
+ show_bottom_topic_map:
+ client: true
+ default: true
+
+ show_topic_map_in_topics_without_replies:
+ client: true
+ default: false
+
user_preferences:
default_email_digest_frequency:
enum: "DigestEmailSiteSetting"
diff --git a/plugins/styleguide/assets/javascripts/discourse/lib/dummy-data.js b/plugins/styleguide/assets/javascripts/discourse/lib/dummy-data.js
index d1fece440cb..980e5a9f31d 100644
--- a/plugins/styleguide/assets/javascripts/discourse/lib/dummy-data.js
+++ b/plugins/styleguide/assets/javascripts/discourse/lib/dummy-data.js
@@ -168,32 +168,7 @@ export function createData(store) {
canBookmark: true,
canManage: true,
canDelete: true,
- createdByUsername: user.username,
- createdByAvatarTemplate: user.avatar_template,
- lastPostUsername: user.username,
- lastPostAvatarTemplate: user.avatar_template,
- topicReplyCount: 123,
- topicViews: 3456,
- participantCount: 10,
- topicLikeCount: 14,
- topicLinkLength: 5,
- topicPostsCount: 4,
- participants: [createUser(), createUser(), createUser(), createUser()],
post_number: 1,
- topicLinks: [
- {
- title: "Evil Trout",
- url: "https://eviltrout.com",
- domain: "eviltrout.com",
- clicks: 1024,
- },
- {
- title: "Cool Site",
- url: "http://coolsite.example.com",
- domain: "coolsite.example.com",
- clicks: 512,
- },
- ],
};
const postModel = store.createRecord("post", {