UX: Small topic map improvements and fixes (#28215)

This commit is contained in:
Jan Cernik 2024-08-12 13:37:05 -05:00 committed by GitHub
parent 157c8e660a
commit 043fc0a117
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 116 additions and 130 deletions

View File

@ -91,18 +91,11 @@ export default class TopicMapSummary extends Component {
if (this.args.topic.has_summary) { if (this.args.topic.has_summary) {
return false; return false;
} }
return [this.hasLikes, this.hasUsers, this.hasLinks].every((stat) => !stat);
return (
[this.hasViews, this.hasLikes, this.hasUsers, this.hasLinks].filter(
Boolean
).length === 1
);
} }
get manyStats() { get manyStats() {
return [this.hasViews, this.hasLikes, this.hasUsers, this.hasLinks].every( return [this.hasLikes, this.hasUsers, this.hasLinks].every(Boolean);
Boolean
);
} }
get shouldShowViewsChart() { get shouldShowViewsChart() {
@ -127,10 +120,6 @@ export default class TopicMapSummary extends Component {
return !this.allLinksShown && this.linksCount > TRUNCATED_LINKS_LIMIT; return !this.allLinksShown && this.linksCount > TRUNCATED_LINKS_LIMIT;
} }
get hasViews() {
return this.args.topic.views > 1;
}
get hasLikes() { get hasLikes() {
return ( return (
this.args.topic.like_count > MIN_LIKES_COUNT && this.args.topic.like_count > MIN_LIKES_COUNT &&
@ -409,7 +398,7 @@ export default class TopicMapSummary extends Component {
<:content> <:content>
<TopicParticipants <TopicParticipants
@title={{i18n "topic_map.participants_title"}} @title={{i18n "topic_map.participants_title"}}
@userFilters={{@userFilters}} @userFilters={{@postStream.userFilters}}
@participants={{@topicDetails.participants}} @participants={{@topicDetails.participants}}
/> />
</:content> </:content>
@ -419,7 +408,7 @@ export default class TopicMapSummary extends Component {
{{#if this.shouldShowParticipants}} {{#if this.shouldShowParticipants}}
<TopicParticipants <TopicParticipants
@participants={{this.first5Participants}} @participants={{this.first5Participants}}
@userFilters={{@userFilters}} @userFilters={{@postStream.userFilters}}
/> />
{{/if}} {{/if}}
<div class="topic-map__buttons"> <div class="topic-map__buttons">

View File

@ -236,7 +236,11 @@ export default class TopicController extends Controller.extend(
@discourseComputed("model.posts_count", "model.postStream.loadingFilter") @discourseComputed("model.posts_count", "model.postStream.loadingFilter")
showBottomTopicMap(postsCount, loading) { showBottomTopicMap(postsCount, loading) {
return !loading && postsCount > MIN_POSTS_COUNT; return (
this.siteSettings.show_bottom_topic_map &&
!loading &&
postsCount > MIN_POSTS_COUNT
);
} }
_removeDeleteOnOwnerReplyBookmarks() { _removeDeleteOnOwnerReplyBookmarks() {

View File

@ -169,64 +169,6 @@ export default function transformPost(
postAtts.requestedGroupName = topic.requested_group_name; 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) { if (postAtts.isDeleted) {
postAtts.deletedByAvatarTemplate = post.get( postAtts.deletedByAvatarTemplate = post.get(
"postDeletedBy.avatar_template" "postDeletedBy.avatar_template"

View File

@ -831,7 +831,7 @@ createWidget("post-article", {
]) ])
); );
if (attrs.showTopicMap) { if (this.shouldShowTopicMap(attrs)) {
rows.push(this.buildTopicMap(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) { buildTopicMap(attrs) {
return new RenderGlimmer( return new RenderGlimmer(
this, this,
@ -917,7 +933,7 @@ createWidget("post-article", {
model: attrs.topic, model: attrs.topic,
topicDetails: attrs.topic.get("details"), topicDetails: attrs.topic.get("details"),
postStream: attrs.topic.postStream, postStream: attrs.topic.postStream,
showPMMap: attrs.showPMMap, showPMMap: attrs.topic.archetype === "private_message",
showInvite: () => this.sendWidgetAction("showInvite"), showInvite: () => this.sendWidgetAction("showInvite"),
removeAllowedGroup: (group) => removeAllowedGroup: (group) =>
this.sendWidgetAction("removeAllowedGroup", group), this.sendWidgetAction("removeAllowedGroup", group),

View File

@ -16,7 +16,13 @@ module("Integration | Component | Widget | post", function (hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
test("basic elements", async function (assert) { 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`<MountWidget @widget="post" @args={{this.args}} />`); await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
@ -771,12 +777,29 @@ module("Integration | Component | Widget | post", function (hooks) {
assert.strictEqual(count("section.embedded-posts .d-icon-arrow-down"), 1); assert.strictEqual(count("section.embedded-posts .d-icon-arrow-down"), 1);
}); });
test("topic map not shown", async function (assert) { test("shows the topic map when setting the 'topicMap' attribute", async function (assert) {
this.set("args", { showTopicMap: false }); 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`<MountWidget @widget="post" @args={{this.args}} />`); await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
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`<MountWidget @widget="post" @args={{this.args}} />`);
assert.dom(".topic-map").exists();
}); });
test("topic map - few participants", async function (assert) { test("topic map - few participants", async function (assert) {
@ -785,6 +808,7 @@ module("Integration | Component | Widget | post", function (hooks) {
id: 123, id: 123,
posts_count: 10, posts_count: 10,
participant_count: 2, participant_count: 2,
archetype: "regular",
}); });
topic.details.set("participants", [ topic.details.set("participants", [
{ username: "eviltrout" }, { username: "eviltrout" },
@ -792,7 +816,7 @@ module("Integration | Component | Widget | post", function (hooks) {
]); ]);
this.set("args", { this.set("args", {
topic, topic,
showTopicMap: true, post_number: 1,
}); });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`); await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
@ -806,6 +830,7 @@ module("Integration | Component | Widget | post", function (hooks) {
id: 123, id: 123,
posts_count: 10, posts_count: 10,
participant_count: 6, participant_count: 6,
archetype: "regular",
}); });
topic.postStream.setProperties({ userFilters: ["sam", "codinghorror"] }); topic.postStream.setProperties({ userFilters: ["sam", "codinghorror"] });
topic.details.set("participants", [ topic.details.set("participants", [
@ -819,7 +844,7 @@ module("Integration | Component | Widget | post", function (hooks) {
this.set("args", { this.set("args", {
topic, topic,
showTopicMap: true, post_number: 1,
}); });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`); await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
@ -833,7 +858,11 @@ module("Integration | Component | Widget | post", function (hooks) {
test("topic map - links", async function (assert) { test("topic map - links", async function (assert) {
const store = getOwner(this).lookup("service:store"); 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", [ topic.details.set("links", [
{ url: "http://link1.example.com", clicks: 0 }, { url: "http://link1.example.com", clicks: 0 },
{ url: "http://link2.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://link5.example.com", clicks: 0 },
{ url: "http://link6.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`<MountWidget @widget="post" @args={{this.args}} />`); await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
@ -857,18 +886,28 @@ module("Integration | Component | Widget | post", function (hooks) {
test("topic map - no top reply summary", async function (assert) { test("topic map - no top reply summary", async function (assert) {
const store = getOwner(this).lookup("service:store"); const store = getOwner(this).lookup("service:store");
const topic = store.createRecord("topic", { id: 123 }); const topic = store.createRecord("topic", {
this.set("args", { topic, showTopicMap: true }); id: 123,
archetype: "regular",
posts_count: 2,
});
this.set("args", { topic, post_number: 1 });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`); await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
assert.dom(".topic-map").exists();
assert.dom(".summarization-button .top-replies").doesNotExist(); assert.dom(".summarization-button .top-replies").doesNotExist();
}); });
test("topic map - has top replies summary", async function (assert) { test("topic map - has top replies summary", async function (assert) {
const store = getOwner(this).lookup("service:store"); const store = getOwner(this).lookup("service:store");
const topic = store.createRecord("topic", { id: 123, has_summary: true }); const topic = store.createRecord("topic", {
this.set("args", { topic, showTopicMap: true }); id: 123,
archetype: "regular",
posts_count: 2,
has_summary: true,
});
this.set("args", { topic, post_number: 1 });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`); await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);
@ -877,14 +916,16 @@ module("Integration | Component | Widget | post", function (hooks) {
test("pm map", async function (assert) { test("pm map", async function (assert) {
const store = getOwner(this).lookup("service:store"); 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", [ topic.details.set("allowed_users", [
EmberObject.create({ username: "eviltrout" }), EmberObject.create({ username: "eviltrout" }),
]); ]);
this.set("args", { this.set("args", {
topic, topic,
showTopicMap: true, post_number: 1,
showPMMap: true,
}); });
await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`); await render(hbs`<MountWidget @widget="post" @args={{this.args}} />`);

View File

@ -2,6 +2,10 @@
// topic map under OP // topic map under OP
border-top: 1px solid var(--primary-low); border-top: 1px solid var(--primary-low);
border-bottom: none; border-bottom: none;
padding-left: calc(
var(--topic-body-width-padding) + var(--topic-avatar-width)
);
} }
.topic-map.--bottom { .topic-map.--bottom {
@ -44,14 +48,13 @@ body:not(.archetype-private_message) {
font-size: var(--font-down-1); font-size: var(--font-down-1);
} }
@media screen and (max-width: 500px) { &.--op,
padding-left: 0; &.--bottom {
@media screen and (max-width: 500px) {
padding-left: 0;
}
} }
padding-left: calc(
var(--topic-body-width-padding) + var(--topic-avatar-width)
);
.--users-summary { .--users-summary {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
@ -158,6 +161,7 @@ body:not(.archetype-private_message) {
.number { .number {
color: var(--tertiary); color: var(--tertiary);
white-space: nowrap;
} }
.topic-map__stat-label { .topic-map__stat-label {
@ -310,9 +314,10 @@ body:not(.archetype-private_message) {
// DMenu popups // DMenu popups
.topic-map__likes-content { .topic-map__likes-content.fk-d-menu__content {
.fk-d-menu__inner-content, .fk-d-menu__inner-content,
.d-modal__body { .d-modal__body {
padding-bottom: 0.5em;
ul { ul {
margin: 0; margin: 0;
padding: 0; padding: 0;
@ -455,14 +460,18 @@ body:not(.archetype-private_message) {
color: var(--primary-medium); color: var(--primary-medium);
} }
.link-summary .btn { .link-summary {
width: 100%; width: 100%;
.d-icon {
color: var(--primary-high); .btn {
} width: 100%;
.discourse-no-touch & { .d-icon {
&:hover { color: var(--primary-high);
background: var(--primary-low); }
.discourse-no-touch & {
&:hover {
background: var(--primary-low);
}
} }
} }
} }

View File

@ -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_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." 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)." 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" 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." navigation_menu: "Specify sidebar or header dropdown as the main navigation menu for your site. Sidebar is recommended."

View File

@ -2976,6 +2976,14 @@ uncategorized:
client: true client: true
default: true default: true
show_bottom_topic_map:
client: true
default: true
show_topic_map_in_topics_without_replies:
client: true
default: false
user_preferences: user_preferences:
default_email_digest_frequency: default_email_digest_frequency:
enum: "DigestEmailSiteSetting" enum: "DigestEmailSiteSetting"

View File

@ -168,32 +168,7 @@ export function createData(store) {
canBookmark: true, canBookmark: true,
canManage: true, canManage: true,
canDelete: 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, 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", { const postModel = store.createRecord("post", {