UX: Topic recommendations tweaks. (#22880)
This PR updates how we display related and suggested topics on mobile and desktop. It adds a new `PluginOutlet` specifically designed for adding new topic lists, which automatically work if following the same conventions as the ones inside `<MoreTopics />`. While we display lists side by side on desktop, we only display one in mobile. You can switch to another one by clicking on the nav pills, and we'll automatically save your preference for next time.
This commit is contained in:
parent
318bdbdb46
commit
e7fb4be23e
|
@ -0,0 +1,40 @@
|
|||
<div
|
||||
class="more-content-wrapper
|
||||
{{if this.showTitleOnMobile 'mobile-single-list'}}"
|
||||
{{did-insert this.buildListPills}}
|
||||
>
|
||||
{{#if this.showTopicListsNav}}
|
||||
<div class="row">
|
||||
<ul class="nav nav-pills" {{did-insert this.buildListPills}}>
|
||||
{{#each this.availablePills as |pill|}}
|
||||
<li>
|
||||
<DButton
|
||||
@translatedTitle={{pill.name}}
|
||||
@translatedLabel={{pill.name}}
|
||||
@class={{if pill.selected "active"}}
|
||||
@action={{action "rememberTopicListPreference" pill.id}}
|
||||
/>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if @topic.relatedMessages.length}}
|
||||
<RelatedMessages @topic={{@topic}} />
|
||||
{{/if}}
|
||||
|
||||
{{#if @topic.suggestedTopics.length}}
|
||||
<SuggestedTopics @topic={{@topic}} />
|
||||
|
||||
<span>
|
||||
<PluginOutlet
|
||||
@name="below-suggested-topics"
|
||||
@connectorTagName="div"
|
||||
@outletArgs={{hash topic=@topic}}
|
||||
/>
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
<PluginOutlet @name="topic-more-content" @outletArgs={{hash model=@topic}} />
|
||||
</div>
|
|
@ -0,0 +1,64 @@
|
|||
import Component from "@glimmer/component";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { next } from "@ember/runloop";
|
||||
import { action } from "@ember/object";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
|
||||
export default class MoreTopics extends Component {
|
||||
@service site;
|
||||
@service moreTopicsPreferenceTracking;
|
||||
|
||||
@tracked availablePills = [];
|
||||
@tracked singleList = false;
|
||||
|
||||
get showTopicListsNav() {
|
||||
return this.site.mobileView && !this.singleList;
|
||||
}
|
||||
|
||||
get showTitleOnMobile() {
|
||||
return this.site.mobileView && this.singleList;
|
||||
}
|
||||
|
||||
@action
|
||||
rememberTopicListPreference(value) {
|
||||
this.moreTopicsPreferenceTracking.updatePreference(value);
|
||||
|
||||
this.buildListPills();
|
||||
}
|
||||
|
||||
@action
|
||||
buildListPills() {
|
||||
if (!this.site.mobileView) {
|
||||
return;
|
||||
}
|
||||
|
||||
next(() => {
|
||||
const pills = Array.from(
|
||||
document.querySelectorAll(".more-content-topics")
|
||||
).map((topicList) => {
|
||||
return {
|
||||
name: topicList.dataset.mobileTitle,
|
||||
id: topicList.dataset.listId,
|
||||
};
|
||||
});
|
||||
|
||||
if (pills.length <= 1) {
|
||||
this.singleList = true;
|
||||
return;
|
||||
}
|
||||
|
||||
let preference = this.moreTopicsPreferenceTracking.preference;
|
||||
|
||||
if (!preference) {
|
||||
this.moreTopicsPreferenceTracking.updatePreference(pills[0].id);
|
||||
preference = pills[0].id;
|
||||
}
|
||||
|
||||
pills.forEach((pill) => {
|
||||
pill.selected = pill.id === preference;
|
||||
});
|
||||
|
||||
this.availablePills = pills;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,10 +1,12 @@
|
|||
<div
|
||||
id="related-messages"
|
||||
class="suggested-topics"
|
||||
class="more-content-topics {{if this.hidden 'hidden'}}"
|
||||
role="complementary"
|
||||
aria-labelledby="related-messages-title"
|
||||
data-mobile-title={{i18n "related_messages.pill"}}
|
||||
data-list-id={{this.listId}}
|
||||
>
|
||||
<h3 class="suggested-topics-title" id="related-messages-title">
|
||||
<h3 id="related-messages-title" class="more-topics-title">
|
||||
{{i18n "related_messages.title"}}
|
||||
</h3>
|
||||
|
||||
|
|
|
@ -1,9 +1,17 @@
|
|||
import Component from "@ember/component";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import getURL from "discourse-common/lib/get-url";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "",
|
||||
moreTopicsPreferenceTracking: service(),
|
||||
listId: "related-Messages",
|
||||
|
||||
@discourseComputed("moreTopicsPreferenceTracking.preference")
|
||||
hidden(preference) {
|
||||
return this.site.mobileView && preference !== this.listId;
|
||||
},
|
||||
|
||||
@discourseComputed("topic")
|
||||
targetUser(topic) {
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
<div
|
||||
id="suggested-topics"
|
||||
class="suggested-topics"
|
||||
class="more-content-topics {{if this.hidden 'hidden'}}"
|
||||
role="complementary"
|
||||
aria-labelledby="suggested-topics-title"
|
||||
data-mobile-title={{i18n "suggested_topics.pill"}}
|
||||
data-list-id={{this.listId}}
|
||||
>
|
||||
<UserTip @id="suggested_topics" @selector=".user-tip-reference" />
|
||||
|
||||
<h3 id="suggested-topics-title" class="suggested-topics-title">
|
||||
<h3 id="suggested-topics-title" class="more-topics-title">
|
||||
{{i18n this.suggestedTitleLabel}}
|
||||
</h3>
|
||||
|
||||
|
@ -25,12 +27,4 @@
|
|||
<h3 class="suggested-topics-message">
|
||||
{{html-safe this.browseMoreMessage}}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<span>
|
||||
<PluginOutlet
|
||||
@name="below-suggested-topics"
|
||||
@connectorTagName="div"
|
||||
@outletArgs={{hash topic=this.topic}}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
|
@ -5,9 +5,12 @@ import { categoryBadgeHTML } from "discourse/helpers/category-link";
|
|||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import getURL from "discourse-common/lib/get-url";
|
||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "",
|
||||
moreTopicsPreferenceTracking: service(),
|
||||
listId: "suggested-topics",
|
||||
|
||||
suggestedTitleLabel: computed("topic", function () {
|
||||
const href = this.currentUser && this.currentUser.pmPath(this.topic);
|
||||
|
@ -18,6 +21,11 @@ export default Component.extend({
|
|||
}
|
||||
}),
|
||||
|
||||
@discourseComputed("moreTopicsPreferenceTracking.preference")
|
||||
hidden(preference) {
|
||||
return this.site.mobileView && preference !== this.listId;
|
||||
},
|
||||
|
||||
@discourseComputed(
|
||||
"topic",
|
||||
"pmTopicTrackingState.isTracking",
|
||||
|
|
|
@ -360,7 +360,7 @@ export default {
|
|||
},
|
||||
|
||||
goToFirstSuggestedTopic() {
|
||||
const el = document.querySelector(".suggested-topics a.raw-topic-link");
|
||||
const el = document.querySelector("#suggested-topics a.raw-topic-link");
|
||||
if (el) {
|
||||
el.click();
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
import Service, { inject as service } from "@ember/service";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
|
||||
const TOPIC_LIST_PREFERENCE_KEY = "more-topics-list-preference";
|
||||
|
||||
export default class MoreTopicsPreferenceTracking extends Service {
|
||||
@service keyValueStore;
|
||||
|
||||
@tracked preference;
|
||||
|
||||
init() {
|
||||
super.init(...arguments);
|
||||
this.preference = this.keyValueStore.get(TOPIC_LIST_PREFERENCE_KEY);
|
||||
}
|
||||
|
||||
updatePreference(value) {
|
||||
this.keyValueStore.set({ key: TOPIC_LIST_PREFERENCE_KEY, value });
|
||||
this.preference = value;
|
||||
}
|
||||
}
|
|
@ -543,20 +543,8 @@
|
|||
@outletArgs={{hash model=this.model}}
|
||||
/>
|
||||
</span>
|
||||
<div
|
||||
class="{{if
|
||||
this.model.relatedMessages.length
|
||||
'related-messages-wrapper'
|
||||
}}
|
||||
{{if this.model.suggestedTopics.length 'suggested-topics-wrapper'}}"
|
||||
>
|
||||
{{#if this.model.relatedMessages.length}}
|
||||
<RelatedMessages @topic={{this.model}} />
|
||||
{{/if}}
|
||||
{{#if this.model.suggestedTopics.length}}
|
||||
<SuggestedTopics @topic={{this.model}} />
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<MoreTopics @topic={{this.model}} />
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<div class="container">
|
||||
|
|
|
@ -21,7 +21,7 @@ acceptance("Personal Message", function (needs) {
|
|||
await visit("/t/pm-for-testing/12");
|
||||
|
||||
assert.strictEqual(
|
||||
query("#suggested-topics .suggested-topics-title").innerText.trim(),
|
||||
query("#suggested-topics-title").innerText.trim(),
|
||||
I18n.t("suggested_topics.pm_title")
|
||||
);
|
||||
});
|
||||
|
|
|
@ -204,7 +204,7 @@ acceptance("Topic", function (needs) {
|
|||
await visit("/t/internationalization-localization/280");
|
||||
|
||||
assert.strictEqual(
|
||||
query("#suggested-topics .suggested-topics-title").innerText.trim(),
|
||||
query("#suggested-topics-title").innerText.trim(),
|
||||
I18n.t("suggested_topics.title")
|
||||
);
|
||||
});
|
||||
|
|
|
@ -83,242 +83,246 @@ acceptance(
|
|||
}
|
||||
);
|
||||
|
||||
acceptance(
|
||||
"User Private Messages - user with group messages",
|
||||
function (needs) {
|
||||
let fetchedNew;
|
||||
let fetchUserNew;
|
||||
let fetchedGroupNew;
|
||||
let fetchedNew;
|
||||
let fetchUserNew;
|
||||
let fetchedGroupNew;
|
||||
|
||||
needs.user({
|
||||
id: 5,
|
||||
username: "charlie",
|
||||
groups: [{ id: 14, name: "awesome_group", has_messages: true }],
|
||||
function withGroupMessagesSetup(needs) {
|
||||
needs.user({
|
||||
id: 5,
|
||||
username: "charlie",
|
||||
groups: [{ id: 14, name: "awesome_group", has_messages: true }],
|
||||
});
|
||||
|
||||
needs.site({
|
||||
can_tag_pms: true,
|
||||
});
|
||||
|
||||
needs.hooks.afterEach(() => {
|
||||
fetchedNew = false;
|
||||
fetchedGroupNew = false;
|
||||
fetchUserNew = false;
|
||||
});
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
server.get("/tags/personal_messages/:username.json", () => {
|
||||
return helper.response({ tags: [{ id: "tag1" }] });
|
||||
});
|
||||
|
||||
needs.site({
|
||||
can_tag_pms: true,
|
||||
server.get("/t/13.json", () => {
|
||||
const response = cloneJSON(fixturesByUrl["/t/12/1.json"]);
|
||||
response.suggested_group_name = "awesome_group";
|
||||
return helper.response(response);
|
||||
});
|
||||
|
||||
needs.hooks.afterEach(() => {
|
||||
fetchedNew = false;
|
||||
fetchedGroupNew = false;
|
||||
fetchUserNew = false;
|
||||
});
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
server.get("/tags/personal_messages/:username.json", () => {
|
||||
return helper.response({ tags: [{ id: "tag1" }] });
|
||||
server.get("/topics/private-messages/:username.json", () => {
|
||||
return helper.response({
|
||||
topic_list: {
|
||||
topics: [
|
||||
{
|
||||
id: 1,
|
||||
posters: [],
|
||||
notification_level: NotificationLevels.TRACKING,
|
||||
unread_posts: 1,
|
||||
last_read_post_number: 1,
|
||||
highest_post_number: 2,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
posters: [],
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
posters: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
server.get("/t/13.json", () => {
|
||||
const response = cloneJSON(fixturesByUrl["/t/12/1.json"]);
|
||||
response.suggested_group_name = "awesome_group";
|
||||
return helper.response(response);
|
||||
[
|
||||
"/topics/private-messages-new/:username.json",
|
||||
"/topics/private-messages-unread/:username.json",
|
||||
"/topics/private-messages-archive/:username.json",
|
||||
"/topics/private-messages-group/:username/:group_name/new.json",
|
||||
"/topics/private-messages-group/:username/:group_name/unread.json",
|
||||
"/topics/private-messages-group/:username/:group_name/archive.json",
|
||||
"/topics/private-messages-tags/:username/:tag_name",
|
||||
].forEach((url) => {
|
||||
server.get(url, () => {
|
||||
let topics;
|
||||
|
||||
if (fetchedNew || fetchedGroupNew || fetchUserNew) {
|
||||
topics = [];
|
||||
} else {
|
||||
topics = [
|
||||
{ id: 1, posters: [] },
|
||||
{ id: 2, posters: [] },
|
||||
{ id: 3, posters: [] },
|
||||
];
|
||||
}
|
||||
|
||||
return helper.response({
|
||||
topic_list: {
|
||||
topics,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
server.get("/topics/private-messages/:username.json", () => {
|
||||
server.get(
|
||||
"/topics/private-messages-group/:username/:group_name.json",
|
||||
() => {
|
||||
return helper.response({
|
||||
topic_list: {
|
||||
topics: [
|
||||
{
|
||||
id: 1,
|
||||
posters: [],
|
||||
notification_level: NotificationLevels.TRACKING,
|
||||
unread_posts: 1,
|
||||
last_read_post_number: 1,
|
||||
highest_post_number: 2,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
posters: [],
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
posters: [],
|
||||
},
|
||||
{ id: 1, posters: [] },
|
||||
{ id: 2, posters: [] },
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
[
|
||||
"/topics/private-messages-new/:username.json",
|
||||
"/topics/private-messages-unread/:username.json",
|
||||
"/topics/private-messages-archive/:username.json",
|
||||
"/topics/private-messages-group/:username/:group_name/new.json",
|
||||
"/topics/private-messages-group/:username/:group_name/unread.json",
|
||||
"/topics/private-messages-group/:username/:group_name/archive.json",
|
||||
"/topics/private-messages-tags/:username/:tag_name",
|
||||
].forEach((url) => {
|
||||
server.get(url, () => {
|
||||
let topics;
|
||||
server.put("/topics/pm-reset-new", (request) => {
|
||||
const requestBody = request.requestBody;
|
||||
// No easy way to do this https://github.com/pretenderjs/pretender/issues/159
|
||||
if (requestBody === "inbox=group&group_name=awesome_group") {
|
||||
fetchedGroupNew = true;
|
||||
}
|
||||
|
||||
if (fetchedNew || fetchedGroupNew || fetchUserNew) {
|
||||
topics = [];
|
||||
} else {
|
||||
topics = [
|
||||
{ id: 1, posters: [] },
|
||||
{ id: 2, posters: [] },
|
||||
{ id: 3, posters: [] },
|
||||
];
|
||||
}
|
||||
if (requestBody === "inbox=user") {
|
||||
fetchUserNew = true;
|
||||
}
|
||||
|
||||
return helper.response({
|
||||
topic_list: {
|
||||
topics,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
if (requestBody === "inbox=all") {
|
||||
fetchedNew = true;
|
||||
}
|
||||
|
||||
server.get(
|
||||
"/topics/private-messages-group/:username/:group_name.json",
|
||||
() => {
|
||||
return helper.response({
|
||||
topic_list: {
|
||||
topics: [
|
||||
{ id: 1, posters: [] },
|
||||
{ id: 2, posters: [] },
|
||||
],
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
server.put("/topics/pm-reset-new", (request) => {
|
||||
const requestBody = request.requestBody;
|
||||
// No easy way to do this https://github.com/pretenderjs/pretender/issues/159
|
||||
if (requestBody === "inbox=group&group_name=awesome_group") {
|
||||
fetchedGroupNew = true;
|
||||
}
|
||||
|
||||
if (requestBody === "inbox=user") {
|
||||
fetchUserNew = true;
|
||||
}
|
||||
|
||||
if (requestBody === "inbox=all") {
|
||||
fetchedNew = true;
|
||||
}
|
||||
|
||||
return helper.response({ topic_ids: [1, 2, 3] });
|
||||
});
|
||||
|
||||
server.put("/topics/bulk", (request) => {
|
||||
const requestBody = request.requestBody;
|
||||
|
||||
if (requestBody.includes("private_message_inbox=all")) {
|
||||
fetchedNew = true;
|
||||
}
|
||||
|
||||
if (
|
||||
requestBody.includes(
|
||||
"private_message_inbox=group&group_name=awesome_group"
|
||||
)
|
||||
) {
|
||||
fetchedGroupNew = true;
|
||||
}
|
||||
|
||||
if (requestBody.includes("private_message_inbox=user")) {
|
||||
fetchUserNew = true;
|
||||
}
|
||||
|
||||
return helper.response({
|
||||
topic_ids: [1, 2, 3],
|
||||
});
|
||||
});
|
||||
return helper.response({ topic_ids: [1, 2, 3] });
|
||||
});
|
||||
|
||||
const publishReadToMessageBus = function (opts = {}) {
|
||||
return publishToMessageBus(
|
||||
`/private-message-topic-tracking-state/user/${opts.userId || 5}`,
|
||||
{
|
||||
topic_id: opts.topicId,
|
||||
message_type: "read",
|
||||
payload: {
|
||||
last_read_post_number: 2,
|
||||
highest_post_number: 2,
|
||||
notification_level: 2,
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
server.put("/topics/bulk", (request) => {
|
||||
const requestBody = request.requestBody;
|
||||
|
||||
const publishUnreadToMessageBus = function (opts = {}) {
|
||||
return publishToMessageBus(
|
||||
`/private-message-topic-tracking-state/user/${opts.userId || 5}`,
|
||||
{
|
||||
topic_id: opts.topicId,
|
||||
message_type: "unread",
|
||||
payload: {
|
||||
last_read_post_number: 1,
|
||||
highest_post_number: 2,
|
||||
notification_level: 2,
|
||||
group_ids: opts.groupIds || [],
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
if (requestBody.includes("private_message_inbox=all")) {
|
||||
fetchedNew = true;
|
||||
}
|
||||
|
||||
const publishNewToMessageBus = function (opts = {}) {
|
||||
return publishToMessageBus(
|
||||
`/private-message-topic-tracking-state/user/${opts.userId || 5}`,
|
||||
{
|
||||
topic_id: opts.topicId,
|
||||
message_type: "new_topic",
|
||||
payload: {
|
||||
last_read_post_number: null,
|
||||
highest_post_number: 1,
|
||||
group_ids: opts.groupIds || [],
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
if (
|
||||
requestBody.includes(
|
||||
"private_message_inbox=group&group_name=awesome_group"
|
||||
)
|
||||
) {
|
||||
fetchedGroupNew = true;
|
||||
}
|
||||
|
||||
const publishGroupArchiveToMessageBus = function (opts) {
|
||||
return publishToMessageBus(
|
||||
`/private-message-topic-tracking-state/group/${opts.groupIds[0]}`,
|
||||
{
|
||||
topic_id: opts.topicId,
|
||||
message_type: "group_archive",
|
||||
payload: {
|
||||
group_ids: opts.groupIds,
|
||||
acting_user_id: opts.actingUserId,
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
if (requestBody.includes("private_message_inbox=user")) {
|
||||
fetchUserNew = true;
|
||||
}
|
||||
|
||||
const publishGroupUnreadToMessageBus = function (opts) {
|
||||
return publishToMessageBus(
|
||||
`/private-message-topic-tracking-state/group/${opts.groupIds[0]}`,
|
||||
{
|
||||
topic_id: opts.topicId,
|
||||
message_type: "unread",
|
||||
payload: {
|
||||
last_read_post_number: 1,
|
||||
highest_post_number: 2,
|
||||
notification_level: 2,
|
||||
group_ids: opts.groupIds || [],
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
return helper.response({
|
||||
topic_ids: [1, 2, 3],
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const publishGroupNewToMessageBus = function (opts) {
|
||||
return publishToMessageBus(
|
||||
`/private-message-topic-tracking-state/group/${opts.groupIds[0]}`,
|
||||
{
|
||||
topic_id: opts.topicId,
|
||||
message_type: "new_topic",
|
||||
payload: {
|
||||
last_read_post_number: null,
|
||||
highest_post_number: 1,
|
||||
group_ids: opts.groupIds || [],
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
const publishReadToMessageBus = function (opts = {}) {
|
||||
return publishToMessageBus(
|
||||
`/private-message-topic-tracking-state/user/${opts.userId || 5}`,
|
||||
{
|
||||
topic_id: opts.topicId,
|
||||
message_type: "read",
|
||||
payload: {
|
||||
last_read_post_number: 2,
|
||||
highest_post_number: 2,
|
||||
notification_level: 2,
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const publishUnreadToMessageBus = function (opts = {}) {
|
||||
return publishToMessageBus(
|
||||
`/private-message-topic-tracking-state/user/${opts.userId || 5}`,
|
||||
{
|
||||
topic_id: opts.topicId,
|
||||
message_type: "unread",
|
||||
payload: {
|
||||
last_read_post_number: 1,
|
||||
highest_post_number: 2,
|
||||
notification_level: 2,
|
||||
group_ids: opts.groupIds || [],
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const publishNewToMessageBus = function (opts = {}) {
|
||||
return publishToMessageBus(
|
||||
`/private-message-topic-tracking-state/user/${opts.userId || 5}`,
|
||||
{
|
||||
topic_id: opts.topicId,
|
||||
message_type: "new_topic",
|
||||
payload: {
|
||||
last_read_post_number: null,
|
||||
highest_post_number: 1,
|
||||
group_ids: opts.groupIds || [],
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const publishGroupArchiveToMessageBus = function (opts) {
|
||||
return publishToMessageBus(
|
||||
`/private-message-topic-tracking-state/group/${opts.groupIds[0]}`,
|
||||
{
|
||||
topic_id: opts.topicId,
|
||||
message_type: "group_archive",
|
||||
payload: {
|
||||
group_ids: opts.groupIds,
|
||||
acting_user_id: opts.actingUserId,
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const publishGroupUnreadToMessageBus = function (opts) {
|
||||
return publishToMessageBus(
|
||||
`/private-message-topic-tracking-state/group/${opts.groupIds[0]}`,
|
||||
{
|
||||
topic_id: opts.topicId,
|
||||
message_type: "unread",
|
||||
payload: {
|
||||
last_read_post_number: 1,
|
||||
highest_post_number: 2,
|
||||
notification_level: 2,
|
||||
group_ids: opts.groupIds || [],
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const publishGroupNewToMessageBus = function (opts) {
|
||||
return publishToMessageBus(
|
||||
`/private-message-topic-tracking-state/group/${opts.groupIds[0]}`,
|
||||
{
|
||||
topic_id: opts.topicId,
|
||||
message_type: "new_topic",
|
||||
payload: {
|
||||
last_read_post_number: null,
|
||||
highest_post_number: 1,
|
||||
group_ids: opts.groupIds || [],
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
acceptance(
|
||||
"User Private Messages - user with group messages",
|
||||
function (needs) {
|
||||
withGroupMessagesSetup(needs);
|
||||
|
||||
test("incoming group archive message acted by current user", async function (assert) {
|
||||
await visit("/u/charlie/messages");
|
||||
|
@ -639,83 +643,6 @@ acceptance(
|
|||
);
|
||||
});
|
||||
|
||||
test("suggested messages without new or unread", async function (assert) {
|
||||
await visit("/t/12");
|
||||
|
||||
assert.strictEqual(
|
||||
query(".suggested-topics-message").innerText.trim(),
|
||||
"Want to read more? Browse other messages in personal messages.",
|
||||
"displays the right browse more message"
|
||||
);
|
||||
});
|
||||
|
||||
test("suggested messages with new and unread", async function (assert) {
|
||||
await visit("/t/12");
|
||||
|
||||
await publishNewToMessageBus({ userId: 5, topicId: 1 });
|
||||
|
||||
assert.strictEqual(
|
||||
query(".suggested-topics-message").innerText.trim(),
|
||||
"There is 1 new message remaining, or browse other personal messages",
|
||||
"displays the right browse more message"
|
||||
);
|
||||
|
||||
await publishUnreadToMessageBus({ userId: 5, topicId: 2 });
|
||||
|
||||
assert.strictEqual(
|
||||
query(".suggested-topics-message").innerText.trim(),
|
||||
"There is 1 unread and 1 new message remaining, or browse other personal messages",
|
||||
"displays the right browse more message"
|
||||
);
|
||||
|
||||
await publishReadToMessageBus({ userId: 5, topicId: 2 });
|
||||
|
||||
assert.strictEqual(
|
||||
query(".suggested-topics-message").innerText.trim(),
|
||||
"There is 1 new message remaining, or browse other personal messages",
|
||||
"displays the right browse more message"
|
||||
);
|
||||
});
|
||||
|
||||
test("suggested messages for group messages without new or unread", async function (assert) {
|
||||
await visit("/t/13");
|
||||
|
||||
assert.ok(
|
||||
query(".suggested-topics-message")
|
||||
.innerText.trim()
|
||||
.match(
|
||||
/Want to read more\? Browse other messages in\s+awesome_group\./
|
||||
),
|
||||
"displays the right browse more message"
|
||||
);
|
||||
});
|
||||
|
||||
test("suggested messages for group messages with new and unread", async function (assert) {
|
||||
await visit("/t/13");
|
||||
|
||||
await publishGroupNewToMessageBus({ groupIds: [14], topicId: 1 });
|
||||
|
||||
assert.ok(
|
||||
query(".suggested-topics-message")
|
||||
.innerText.trim()
|
||||
.match(
|
||||
/There is 1 new message remaining, or browse other messages in\s+awesome_group/
|
||||
),
|
||||
"displays the right browse more message"
|
||||
);
|
||||
|
||||
await publishGroupUnreadToMessageBus({ groupIds: [14], topicId: 2 });
|
||||
|
||||
assert.ok(
|
||||
query(".suggested-topics-message")
|
||||
.innerText.trim()
|
||||
.match(
|
||||
/There is 1 unread and 1 new message remaining, or browse other messages in\s+awesome_group/
|
||||
),
|
||||
"displays the right browse more message"
|
||||
);
|
||||
});
|
||||
|
||||
test("navigating between user messages route with dropdown", async function (assert) {
|
||||
await visit("/u/Charlie/messages");
|
||||
|
||||
|
@ -808,6 +735,95 @@ acceptance(
|
|||
}
|
||||
);
|
||||
|
||||
acceptance(
|
||||
"User Private Messages - user with group messages - Mobile",
|
||||
function (needs) {
|
||||
withGroupMessagesSetup(needs);
|
||||
needs.mobileView();
|
||||
|
||||
test("suggested messages without new or unread", async function (assert) {
|
||||
await visit("/t/12");
|
||||
|
||||
assert.strictEqual(
|
||||
query(".suggested-topics-message").innerText.trim(),
|
||||
"Want to read more? Browse other messages in personal messages.",
|
||||
"displays the right browse more message"
|
||||
);
|
||||
});
|
||||
|
||||
test("suggested messages with new and unread", async function (assert) {
|
||||
await visit("/t/12");
|
||||
|
||||
await publishNewToMessageBus({ userId: 5, topicId: 1 });
|
||||
|
||||
assert.strictEqual(
|
||||
query(".suggested-topics-message").innerText.trim(),
|
||||
"There is 1 new message remaining, or browse other personal messages",
|
||||
"displays the right browse more message"
|
||||
);
|
||||
|
||||
await publishUnreadToMessageBus({ userId: 5, topicId: 2 });
|
||||
|
||||
assert.ok(
|
||||
query(".suggested-topics-message")
|
||||
.innerText.trim()
|
||||
.match(
|
||||
/There is 1 unread\s+ and 1 new message remaining, or browse other personal messages/
|
||||
),
|
||||
"displays the right browse more message"
|
||||
);
|
||||
|
||||
await publishReadToMessageBus({ userId: 5, topicId: 2 });
|
||||
|
||||
assert.strictEqual(
|
||||
query(".suggested-topics-message").innerText.trim(),
|
||||
"There is 1 new message remaining, or browse other personal messages",
|
||||
"displays the right browse more message"
|
||||
);
|
||||
});
|
||||
|
||||
test("suggested messages for group messages without new or unread", async function (assert) {
|
||||
await visit("/t/13");
|
||||
|
||||
assert.ok(
|
||||
query(".suggested-topics-message")
|
||||
.innerText.trim()
|
||||
.match(
|
||||
/Want to read more\? Browse other messages in\s+awesome_group\./
|
||||
),
|
||||
"displays the right browse more message"
|
||||
);
|
||||
});
|
||||
|
||||
test("suggested messages for group messages with new and unread", async function (assert) {
|
||||
needs.mobileView();
|
||||
await visit("/t/13");
|
||||
|
||||
await publishGroupNewToMessageBus({ groupIds: [14], topicId: 1 });
|
||||
|
||||
assert.ok(
|
||||
query(".suggested-topics-message")
|
||||
.innerText.trim()
|
||||
.match(
|
||||
/There is 1 new message remaining, or browse other messages in\s+awesome_group/
|
||||
),
|
||||
"displays the right browse more message"
|
||||
);
|
||||
|
||||
await publishGroupUnreadToMessageBus({ groupIds: [14], topicId: 2 });
|
||||
|
||||
assert.ok(
|
||||
query(".suggested-topics-message")
|
||||
.innerText.trim()
|
||||
.match(
|
||||
/There is 1 unread\s+ and 1 new message remaining, or browse other messages in\s+awesome_group/
|
||||
),
|
||||
"displays the right browse more message"
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
acceptance("User Private Messages - user with no messages", function (needs) {
|
||||
needs.user();
|
||||
|
||||
|
|
|
@ -368,42 +368,43 @@ a.badge-category {
|
|||
max-width: 757px;
|
||||
}
|
||||
|
||||
.suggested-topics-wrapper.related-messages-wrapper {
|
||||
.suggested-topics:nth-of-type(n + 2) {
|
||||
thead {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.more-content-wrapper .topic-list-body .topic-list-data:first-of-type {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
// Target the .badge-category text, the bullet icon needs to maintain `display: block`
|
||||
.suggested-topics h3 .badge-wrapper.bullet span.badge-category,
|
||||
.suggested-topics h3 .badge-wrapper.box span,
|
||||
.suggested-topics h3 .badge-wrapper.bar span {
|
||||
.more-content-topics h3 .badge-wrapper.bullet span.badge-category,
|
||||
.more-content-topics h3 .badge-wrapper.box span,
|
||||
.more-content-topics h3 .badge-wrapper.bar span {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.suggested-topics h3 .badge-wrapper.bullet span.badge-category {
|
||||
.more-content-topicss h3 .badge-wrapper.bullet span.badge-category {
|
||||
// Override vertical-align: text-top from `badges.css.scss`
|
||||
vertical-align: baseline;
|
||||
line-height: var(--line-height-medium);
|
||||
}
|
||||
|
||||
.suggested-topics h3 .badge-wrapper.bullet,
|
||||
.suggested-topics h3 .badge-wrapper.bullet span.badge-category-parent-bg,
|
||||
.suggested-topics h3 .badge-wrapper.bullet span.badge-category-bg {
|
||||
.more-content-topics h3 .badge-wrapper.bullet,
|
||||
.more-content-topics h3 .badge-wrapper.bullet span.badge-category-parent-bg,
|
||||
.more-content-topics h3 .badge-wrapper.bullet span.badge-category-bg {
|
||||
// Top of bullet aligns with top of line - adjust line height to vertically align bullet.
|
||||
line-height: 0.8;
|
||||
}
|
||||
|
||||
.suggested-topics .badge-wrapper.bullet span.badge-category,
|
||||
.suggested-topics .badge-wrapper.bar span.badge-category {
|
||||
.more-content-topics .badge-wrapper.bullet span.badge-category,
|
||||
.more-content-topics .badge-wrapper.bar span.badge-category {
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
.suggested-topics .suggested-topics-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.more-content-topics {
|
||||
.topic-list-body {
|
||||
border-top: none;
|
||||
|
||||
.topic-list-item:last-of-type {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.post-links-container {
|
||||
|
|
|
@ -362,11 +362,11 @@ pre.codeblock-buttons:hover {
|
|||
}
|
||||
}
|
||||
|
||||
.suggested-topics {
|
||||
margin: 4.5em 0 1em;
|
||||
.more-content-topics {
|
||||
margin-top: 2em;
|
||||
|
||||
table {
|
||||
margin-top: 10px;
|
||||
.suggested-topics-message {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -135,3 +135,21 @@
|
|||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.more-content-wrapper {
|
||||
display: flex;
|
||||
|
||||
.topic-list-header,
|
||||
.posts-map,
|
||||
.views {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.topic-list-body {
|
||||
border-top: none;
|
||||
|
||||
.topic-list-item:last-of-type {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -252,17 +252,18 @@ a.reply-to-tab {
|
|||
}
|
||||
}
|
||||
|
||||
.suggested-topics {
|
||||
.more-content-wrapper {
|
||||
&:not(.mobile-single-list) {
|
||||
.more-topics-title {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.more-content-topics {
|
||||
clear: left;
|
||||
padding: 20px 0 15px 0;
|
||||
th.views,
|
||||
td.views,
|
||||
td.activity,
|
||||
th.activity,
|
||||
th.likes,
|
||||
td.likes {
|
||||
display: none;
|
||||
}
|
||||
|
||||
a.badge-category,
|
||||
a.badge-category-parent {
|
||||
font-size: var(--font-down-1);
|
||||
|
|
|
@ -301,10 +301,12 @@ en:
|
|||
|
||||
related_messages:
|
||||
title: "Related Messages"
|
||||
pill: "Related Messages"
|
||||
see_all: 'See <a href="%{path}">all messages</a> from @%{username}...'
|
||||
|
||||
suggested_topics:
|
||||
title: "Suggested Topics"
|
||||
title: "New & Unread Topics"
|
||||
pill: "Suggested"
|
||||
pm_title: "Suggested Messages"
|
||||
|
||||
about:
|
||||
|
|
Loading…
Reference in New Issue