FEATURE: New/unread messages count in experimental sidebar (#17117)

* FEATURE: Expand messages filter links when viewing private messages.

* FEATURE: New/unread messages count in experimental sidebar
This commit is contained in:
Alan Guo Xiang Tan 2022-06-22 11:01:37 +08:00 committed by GitHub
parent b09cce6897
commit 0b8e6adabe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 278 additions and 15 deletions

View File

@ -2,13 +2,14 @@ import { cached } from "@glimmer/tracking";
import { getOwner } from "discourse-common/lib/get-owner";
import GlimmerComponent from "discourse/components/glimmer";
import { bind } from "discourse-common/utils/decorators";
import GroupMessageSectionLink from "discourse/lib/sidebar/messages-section/group-message-section-link";
import PersonalMessageSectionLink from "discourse/lib/sidebar/messages-section/personal-message-section-link";
export const INBOX = "inbox";
const UNREAD = "unread";
export const UNREAD = "unread";
const SENT = "sent";
const NEW = "new";
export const NEW = "new";
const ARCHIVE = "archive";
export const PERSONAL_MESSAGES_INBOX_FILTERS = [
@ -30,6 +31,24 @@ export default class SidebarMessagesSection extends GlimmerComponent {
this,
this._refreshSectionLinksDisplayState
);
this.pmTopicTrackingState
.startTracking()
.then(this._refreshSectionLinkCounts);
this._pmTopicTrackingStateKey = "messages-section";
this.pmTopicTrackingState.onStateChange(
this._pmTopicTrackingStateKey,
this._refreshSectionLinkCounts
);
}
@bind
_refreshSectionLinkCounts() {
for (const sectionLink of this.allSectionLinks) {
sectionLink.refreshCount();
}
}
willDestroy() {
@ -38,6 +57,11 @@ export default class SidebarMessagesSection extends GlimmerComponent {
this,
this._refreshSectionLinksDisplayState
);
this.pmTopicTrackingState.offStateChange(
this._pmTopicTrackingStateKey,
this._refreshSectionLinkCounts
);
}
_refreshSectionLinksDisplayState({
@ -81,6 +105,7 @@ export default class SidebarMessagesSection extends GlimmerComponent {
new PersonalMessageSectionLink({
currentUser: this.currentUser,
type,
pmTopicTrackingState: this.pmTopicTrackingState,
})
);
});
@ -99,6 +124,7 @@ export default class SidebarMessagesSection extends GlimmerComponent {
group,
type: groupMessageLink,
currentUser: this.currentUser,
pmTopicTrackingState: this.pmTopicTrackingState,
})
);
});

View File

@ -40,6 +40,10 @@ export default class GroupMessageSectionLink extends MessageSectionLink {
get text() {
if (this._isInbox) {
return this.group.name;
} else if (this.count > 0) {
return I18n.t(`sidebar.sections.messages.links.${this.type}_with_count`, {
count: this.count,
});
} else {
return I18n.t(`sidebar.sections.messages.links.${this.type}`);
}

View File

@ -1,18 +1,42 @@
import { tracked } from "@glimmer/tracking";
import { INBOX } from "discourse/components/sidebar/messages-section";
import {
INBOX,
NEW,
UNREAD,
} from "discourse/components/sidebar/messages-section";
export default class MessageSectionLink {
@tracked shouldDisplay = this._isInbox;
@tracked count = 0;
constructor({ group, currentUser, type }) {
constructor({ group, currentUser, type, pmTopicTrackingState }) {
this.group = group;
this.currentUser = currentUser;
this.type = type;
this.pmTopicTrackingState = pmTopicTrackingState;
}
refreshCount() {
this._refreshCount();
}
_refreshCount() {
if (this.shouldDisplay && this._shouldTrack) {
this.count = this.pmTopicTrackingState.lookupCount(this.type, {
inboxFilter: this.group ? "group" : "user",
groupName: this.group?.name,
});
}
}
set setDisplayState(value) {
const changed = this.shouldDisplay !== value;
this.shouldDisplay = value;
if (changed) {
this._refreshCount();
}
}
get inboxFilter() {
@ -43,4 +67,8 @@ export default class MessageSectionLink {
get _isInbox() {
return this.type === INBOX;
}
get _shouldTrack() {
return this.type === NEW || this.type === UNREAD;
}
}

View File

@ -38,8 +38,14 @@ export default class PersonalMessageSectionLink extends MessageSectionLink {
}
get text() {
if (this.count > 0) {
return I18n.t(`sidebar.sections.messages.links.${this.type}_with_count`, {
count: this.count,
});
} else {
return I18n.t(`sidebar.sections.messages.links.${this.type}`);
}
}
pageChanged({ currentRouteName, privateMessageTopic }) {
if (this._isInbox) {

View File

@ -1,3 +1,5 @@
import { Promise } from "rsvp";
import EmberObject from "@ember/object";
import { ajax } from "discourse/lib/ajax";
import { bind, on } from "discourse-common/utils/decorators";
@ -25,16 +27,20 @@ const PrivateMessageTopicTrackingState = EmberObject.extend({
this.statesModificationCounter = 0;
this.isTracking = false;
this.newIncoming = [];
this.stateChangeCallbacks = {};
this.stateChangeCallbacks = new Map();
},
onStateChange(name, callback) {
this.stateChangeCallbacks[name] = callback;
onStateChange(key, callback) {
this.stateChangeCallbacks.set(key, callback);
},
offStateChange(key) {
this.stateChangeCallbacks.delete(key);
},
startTracking() {
if (this.isTracking) {
return;
return Promise.resolve();
}
this._establishChannels();
@ -46,13 +52,13 @@ const PrivateMessageTopicTrackingState = EmberObject.extend({
_establishChannels() {
this.messageBus.subscribe(
this._userChannel(),
this.userChannel(),
this._processMessage.bind(this)
);
this.currentUser.groupsWithMessages?.forEach((group) => {
this.messageBus.subscribe(
this._groupChannel(group.id),
this.groupChannel(group.id),
this._processMessage.bind(this)
);
});
@ -111,11 +117,11 @@ const PrivateMessageTopicTrackingState = EmberObject.extend({
return this.states.get(topicId);
},
_userChannel() {
userChannel() {
return `${this.CHANNEL_PREFIX}/user/${this.currentUser.id}`;
},
_groupChannel(groupId) {
groupChannel(groupId) {
return `${this.CHANNEL_PREFIX}/group/${groupId}`;
},
@ -263,7 +269,7 @@ const PrivateMessageTopicTrackingState = EmberObject.extend({
_afterStateChange() {
this.incrementProperty("statesModificationCounter");
Object.values(this.stateChangeCallbacks).forEach((callback) => callback());
this.stateChangeCallbacks.forEach((callback) => callback());
},
});

View File

@ -1,13 +1,17 @@
import { test } from "qunit";
import I18n from "I18n";
import { click, currentURL, visit } from "@ember/test-helpers";
import { click, currentURL, settled, visit } from "@ember/test-helpers";
import {
acceptance,
exists,
publishToMessageBus,
query,
queryAll,
updateCurrentUser,
} from "discourse/tests/helpers/qunit-helpers";
import { NotificationLevels } from "discourse/lib/notification-levels";
acceptance(
"Sidebar - Messages Section - enable_personal_messages disabled",
@ -355,5 +359,192 @@ acceptance(
"foo_group messages inbox filter links are not shown"
);
});
test("new and unread counts for group messages", async function (assert) {
updateCurrentUser({
groups: [
{
id: 1,
name: "group1",
has_messages: true,
},
],
});
await visit("/");
const pmTopicTrackingState = this.container.lookup(
"pm-topic-tracking-state:main"
);
publishToMessageBus(pmTopicTrackingState.groupChannel(1), {
topic_id: 1,
message_type: "unread",
payload: {
last_read_post_number: 1,
highest_post_number: 2,
notification_level: NotificationLevels.TRACKING,
group_ids: [1],
},
});
publishToMessageBus(pmTopicTrackingState.groupChannel(1), {
topic_id: 2,
message_type: "new_topic",
payload: {
last_read_post_number: null,
highest_post_number: 1,
notification_level: NotificationLevels.TRACKING,
group_ids: [1],
},
});
await click(
".sidebar-section-messages .sidebar-section-link-group-messages-inbox.group1"
);
assert.strictEqual(
query(
".sidebar-section-messages .sidebar-section-link-group-messages-unread.group1"
).textContent.trim(),
I18n.t("sidebar.sections.messages.links.unread_with_count", {
count: 1,
}),
"displays 1 count for group1 unread inbox filter link"
);
assert.strictEqual(
query(
".sidebar-section-messages .sidebar-section-link-group-messages-new.group1"
).textContent.trim(),
I18n.t("sidebar.sections.messages.links.new_with_count", {
count: 1,
}),
"displays 1 count for group1 new inbox filter link"
);
publishToMessageBus(pmTopicTrackingState.groupChannel(1), {
topic_id: 2,
message_type: "read",
payload: {
last_read_post_number: 1,
highest_post_number: 1,
notification_level: NotificationLevels.TRACKING,
group_ids: [1],
},
});
await settled();
assert.strictEqual(
query(
".sidebar-section-messages .sidebar-section-link-group-messages-new.group1"
).textContent.trim(),
I18n.t("sidebar.sections.messages.links.new"),
"removes count for group1 new inbox filter link"
);
});
test("new and unread counts for personal messages", async function (assert) {
await visit("/");
const pmTopicTrackingState = this.container.lookup(
"pm-topic-tracking-state:main"
);
publishToMessageBus(pmTopicTrackingState.userChannel(), {
topic_id: 1,
message_type: "unread",
payload: {
last_read_post_number: 1,
highest_post_number: 2,
notification_level: NotificationLevels.TRACKING,
group_ids: [],
},
});
await settled();
await click(
".sidebar-section-messages .sidebar-section-link-personal-messages-inbox"
);
assert.strictEqual(
query(
".sidebar-section-messages .sidebar-section-link-personal-messages-unread"
).textContent.trim(),
I18n.t("sidebar.sections.messages.links.unread_with_count", {
count: 1,
}),
"displays 1 count for the unread inbox filter link"
);
publishToMessageBus(pmTopicTrackingState.userChannel(), {
topic_id: 2,
message_type: "unread",
payload: {
last_read_post_number: 1,
highest_post_number: 2,
notification_level: NotificationLevels.TRACKING,
group_ids: [],
},
});
await settled();
assert.strictEqual(
query(
".sidebar-section-messages .sidebar-section-link-personal-messages-unread"
).textContent.trim(),
I18n.t("sidebar.sections.messages.links.unread_with_count", {
count: 2,
}),
"displays 2 count for the unread inbox filter link"
);
publishToMessageBus(pmTopicTrackingState.userChannel(), {
topic_id: 3,
message_type: "new_topic",
payload: {
last_read_post_number: null,
highest_post_number: 1,
notification_level: NotificationLevels.TRACKING,
group_ids: [],
},
});
await settled();
assert.strictEqual(
query(
".sidebar-section-messages .sidebar-section-link-personal-messages-new"
).textContent.trim(),
I18n.t("sidebar.sections.messages.links.new_with_count", {
count: 1,
}),
"displays 1 count for the new inbox filter link"
);
publishToMessageBus(pmTopicTrackingState.userChannel(), {
topic_id: 3,
message_type: "read",
payload: {
last_read_post_number: 1,
highest_post_number: 1,
notification_level: NotificationLevels.TRACKING,
group_ids: [],
},
});
await settled();
assert.strictEqual(
query(
".sidebar-section-messages .sidebar-section-link-personal-messages-new"
).textContent.trim(),
I18n.t("sidebar.sections.messages.links.new"),
"removes the count from the new inbox filter link"
);
});
}
);

View File

@ -4051,7 +4051,9 @@ en:
inbox: "Inbox"
sent: "Sent"
new: "New"
new_with_count: "New (%{count})"
unread: "Unread"
unread_with_count: "Unread (%{count})"
archive: "Archive"
tags:
no_tracked_tags: "You are not tracking any tags."