mirror of
https://github.com/discourse/discourse.git
synced 2025-03-23 11:45:40 +08:00
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:
parent
b09cce6897
commit
0b8e6adabe
@ -2,13 +2,14 @@ import { cached } from "@glimmer/tracking";
|
|||||||
|
|
||||||
import { getOwner } from "discourse-common/lib/get-owner";
|
import { getOwner } from "discourse-common/lib/get-owner";
|
||||||
import GlimmerComponent from "discourse/components/glimmer";
|
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 GroupMessageSectionLink from "discourse/lib/sidebar/messages-section/group-message-section-link";
|
||||||
import PersonalMessageSectionLink from "discourse/lib/sidebar/messages-section/personal-message-section-link";
|
import PersonalMessageSectionLink from "discourse/lib/sidebar/messages-section/personal-message-section-link";
|
||||||
|
|
||||||
export const INBOX = "inbox";
|
export const INBOX = "inbox";
|
||||||
const UNREAD = "unread";
|
export const UNREAD = "unread";
|
||||||
const SENT = "sent";
|
const SENT = "sent";
|
||||||
const NEW = "new";
|
export const NEW = "new";
|
||||||
const ARCHIVE = "archive";
|
const ARCHIVE = "archive";
|
||||||
|
|
||||||
export const PERSONAL_MESSAGES_INBOX_FILTERS = [
|
export const PERSONAL_MESSAGES_INBOX_FILTERS = [
|
||||||
@ -30,6 +31,24 @@ export default class SidebarMessagesSection extends GlimmerComponent {
|
|||||||
this,
|
this,
|
||||||
this._refreshSectionLinksDisplayState
|
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() {
|
willDestroy() {
|
||||||
@ -38,6 +57,11 @@ export default class SidebarMessagesSection extends GlimmerComponent {
|
|||||||
this,
|
this,
|
||||||
this._refreshSectionLinksDisplayState
|
this._refreshSectionLinksDisplayState
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.pmTopicTrackingState.offStateChange(
|
||||||
|
this._pmTopicTrackingStateKey,
|
||||||
|
this._refreshSectionLinkCounts
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_refreshSectionLinksDisplayState({
|
_refreshSectionLinksDisplayState({
|
||||||
@ -81,6 +105,7 @@ export default class SidebarMessagesSection extends GlimmerComponent {
|
|||||||
new PersonalMessageSectionLink({
|
new PersonalMessageSectionLink({
|
||||||
currentUser: this.currentUser,
|
currentUser: this.currentUser,
|
||||||
type,
|
type,
|
||||||
|
pmTopicTrackingState: this.pmTopicTrackingState,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -99,6 +124,7 @@ export default class SidebarMessagesSection extends GlimmerComponent {
|
|||||||
group,
|
group,
|
||||||
type: groupMessageLink,
|
type: groupMessageLink,
|
||||||
currentUser: this.currentUser,
|
currentUser: this.currentUser,
|
||||||
|
pmTopicTrackingState: this.pmTopicTrackingState,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -40,6 +40,10 @@ export default class GroupMessageSectionLink extends MessageSectionLink {
|
|||||||
get text() {
|
get text() {
|
||||||
if (this._isInbox) {
|
if (this._isInbox) {
|
||||||
return this.group.name;
|
return this.group.name;
|
||||||
|
} else if (this.count > 0) {
|
||||||
|
return I18n.t(`sidebar.sections.messages.links.${this.type}_with_count`, {
|
||||||
|
count: this.count,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
return I18n.t(`sidebar.sections.messages.links.${this.type}`);
|
return I18n.t(`sidebar.sections.messages.links.${this.type}`);
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,42 @@
|
|||||||
import { tracked } from "@glimmer/tracking";
|
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 {
|
export default class MessageSectionLink {
|
||||||
@tracked shouldDisplay = this._isInbox;
|
@tracked shouldDisplay = this._isInbox;
|
||||||
|
@tracked count = 0;
|
||||||
|
|
||||||
constructor({ group, currentUser, type }) {
|
constructor({ group, currentUser, type, pmTopicTrackingState }) {
|
||||||
this.group = group;
|
this.group = group;
|
||||||
this.currentUser = currentUser;
|
this.currentUser = currentUser;
|
||||||
this.type = type;
|
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) {
|
set setDisplayState(value) {
|
||||||
|
const changed = this.shouldDisplay !== value;
|
||||||
this.shouldDisplay = value;
|
this.shouldDisplay = value;
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
this._refreshCount();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get inboxFilter() {
|
get inboxFilter() {
|
||||||
@ -43,4 +67,8 @@ export default class MessageSectionLink {
|
|||||||
get _isInbox() {
|
get _isInbox() {
|
||||||
return this.type === INBOX;
|
return this.type === INBOX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get _shouldTrack() {
|
||||||
|
return this.type === NEW || this.type === UNREAD;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,8 +38,14 @@ export default class PersonalMessageSectionLink extends MessageSectionLink {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get text() {
|
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}`);
|
return I18n.t(`sidebar.sections.messages.links.${this.type}`);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pageChanged({ currentRouteName, privateMessageTopic }) {
|
pageChanged({ currentRouteName, privateMessageTopic }) {
|
||||||
if (this._isInbox) {
|
if (this._isInbox) {
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { Promise } from "rsvp";
|
||||||
|
|
||||||
import EmberObject from "@ember/object";
|
import EmberObject from "@ember/object";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import { bind, on } from "discourse-common/utils/decorators";
|
import { bind, on } from "discourse-common/utils/decorators";
|
||||||
@ -25,16 +27,20 @@ const PrivateMessageTopicTrackingState = EmberObject.extend({
|
|||||||
this.statesModificationCounter = 0;
|
this.statesModificationCounter = 0;
|
||||||
this.isTracking = false;
|
this.isTracking = false;
|
||||||
this.newIncoming = [];
|
this.newIncoming = [];
|
||||||
this.stateChangeCallbacks = {};
|
this.stateChangeCallbacks = new Map();
|
||||||
},
|
},
|
||||||
|
|
||||||
onStateChange(name, callback) {
|
onStateChange(key, callback) {
|
||||||
this.stateChangeCallbacks[name] = callback;
|
this.stateChangeCallbacks.set(key, callback);
|
||||||
|
},
|
||||||
|
|
||||||
|
offStateChange(key) {
|
||||||
|
this.stateChangeCallbacks.delete(key);
|
||||||
},
|
},
|
||||||
|
|
||||||
startTracking() {
|
startTracking() {
|
||||||
if (this.isTracking) {
|
if (this.isTracking) {
|
||||||
return;
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
this._establishChannels();
|
this._establishChannels();
|
||||||
@ -46,13 +52,13 @@ const PrivateMessageTopicTrackingState = EmberObject.extend({
|
|||||||
|
|
||||||
_establishChannels() {
|
_establishChannels() {
|
||||||
this.messageBus.subscribe(
|
this.messageBus.subscribe(
|
||||||
this._userChannel(),
|
this.userChannel(),
|
||||||
this._processMessage.bind(this)
|
this._processMessage.bind(this)
|
||||||
);
|
);
|
||||||
|
|
||||||
this.currentUser.groupsWithMessages?.forEach((group) => {
|
this.currentUser.groupsWithMessages?.forEach((group) => {
|
||||||
this.messageBus.subscribe(
|
this.messageBus.subscribe(
|
||||||
this._groupChannel(group.id),
|
this.groupChannel(group.id),
|
||||||
this._processMessage.bind(this)
|
this._processMessage.bind(this)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -111,11 +117,11 @@ const PrivateMessageTopicTrackingState = EmberObject.extend({
|
|||||||
return this.states.get(topicId);
|
return this.states.get(topicId);
|
||||||
},
|
},
|
||||||
|
|
||||||
_userChannel() {
|
userChannel() {
|
||||||
return `${this.CHANNEL_PREFIX}/user/${this.currentUser.id}`;
|
return `${this.CHANNEL_PREFIX}/user/${this.currentUser.id}`;
|
||||||
},
|
},
|
||||||
|
|
||||||
_groupChannel(groupId) {
|
groupChannel(groupId) {
|
||||||
return `${this.CHANNEL_PREFIX}/group/${groupId}`;
|
return `${this.CHANNEL_PREFIX}/group/${groupId}`;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -263,7 +269,7 @@ const PrivateMessageTopicTrackingState = EmberObject.extend({
|
|||||||
|
|
||||||
_afterStateChange() {
|
_afterStateChange() {
|
||||||
this.incrementProperty("statesModificationCounter");
|
this.incrementProperty("statesModificationCounter");
|
||||||
Object.values(this.stateChangeCallbacks).forEach((callback) => callback());
|
this.stateChangeCallbacks.forEach((callback) => callback());
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
import { test } from "qunit";
|
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 {
|
import {
|
||||||
acceptance,
|
acceptance,
|
||||||
exists,
|
exists,
|
||||||
|
publishToMessageBus,
|
||||||
|
query,
|
||||||
queryAll,
|
queryAll,
|
||||||
updateCurrentUser,
|
updateCurrentUser,
|
||||||
} from "discourse/tests/helpers/qunit-helpers";
|
} from "discourse/tests/helpers/qunit-helpers";
|
||||||
|
import { NotificationLevels } from "discourse/lib/notification-levels";
|
||||||
|
|
||||||
acceptance(
|
acceptance(
|
||||||
"Sidebar - Messages Section - enable_personal_messages disabled",
|
"Sidebar - Messages Section - enable_personal_messages disabled",
|
||||||
@ -355,5 +359,192 @@ acceptance(
|
|||||||
"foo_group messages inbox filter links are not shown"
|
"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"
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -4051,7 +4051,9 @@ en:
|
|||||||
inbox: "Inbox"
|
inbox: "Inbox"
|
||||||
sent: "Sent"
|
sent: "Sent"
|
||||||
new: "New"
|
new: "New"
|
||||||
|
new_with_count: "New (%{count})"
|
||||||
unread: "Unread"
|
unread: "Unread"
|
||||||
|
unread_with_count: "Unread (%{count})"
|
||||||
archive: "Archive"
|
archive: "Archive"
|
||||||
tags:
|
tags:
|
||||||
no_tracked_tags: "You are not tracking any tags."
|
no_tracked_tags: "You are not tracking any tags."
|
||||||
|
Loading…
x
Reference in New Issue
Block a user