mirror of
https://github.com/discourse/discourse.git
synced 2025-03-01 08:49:20 +00:00
FIX: Avoid leaking TopicTrackingState listeners due to sidebar (#18131)
In eb12daa7f8793092bf4fe0c180a04fa3ea2d13e1 when adding community section support for anonymous users, we changed the `sectionLinks` property into a getter method. This meant that if the getter method was called again after the community section has been rendered, we would end up reintializing the section links classes. As part of the initialisation, some section links would setup a TopicTrackingState onStateChange listener. However, the listener is only removed when the entire community section is removed which resulted in us leaking the onStateChange listeners. This commit reverts the `sectionLinks` from being defined as a getter method into a property which is only set once when the community section is being constructor. Also, we changed it such that the community section will register the listener instead of each section link since it makes cleaning up much easier to reason about. No tests have been added for this commit because the original bug is not possible after this change and we already have an existing tests ensuring that TopicTrackingState change listeners are cleaned up when the community section is destroyed. Internal ref: /t/73224
This commit is contained in:
parent
417f156f6d
commit
c245b74398
@ -7,18 +7,16 @@ import UsersSectionLink from "discourse/lib/sidebar/common/community-section/use
|
||||
import BadgesSectionLink from "discourse/lib/sidebar/common/community-section/badges-section-link";
|
||||
|
||||
export default class SidebarAnonymousCommunitySection extends SidebarCommonCommunitySection {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
|
||||
this.defaultMoreSectionLinks = [GroupsSectionLink, BadgesSectionLink];
|
||||
|
||||
this.defaultMoreSecondarySectionLinks = [];
|
||||
|
||||
this.defaultMainSectionLinks = [
|
||||
get defaultMainSectionLinks() {
|
||||
return [
|
||||
EverythingSectionLink,
|
||||
UsersSectionLink,
|
||||
AboutSectionLink,
|
||||
FAQSectionLink,
|
||||
];
|
||||
}
|
||||
|
||||
get defaultMoreSectionLinks() {
|
||||
return [GroupsSectionLink, BadgesSectionLink];
|
||||
}
|
||||
}
|
||||
|
@ -13,45 +13,68 @@ export default class SidebarCommunitySection extends Component {
|
||||
@service appEvents;
|
||||
@service siteSettings;
|
||||
|
||||
// Override in child
|
||||
defaultMainSectionLinks = [];
|
||||
defaultAdminMainSectionLinks = [];
|
||||
defaultMoreSectionLinks = [];
|
||||
defaultMoreSecondarySectionLinks = [];
|
||||
headerActionsIcon;
|
||||
headerActions;
|
||||
sectionLinks;
|
||||
moreSectionLinks;
|
||||
moreSecondarySectionLinks;
|
||||
callbackId;
|
||||
|
||||
get moreSectionLinks() {
|
||||
return [...this.defaultMoreSectionLinks, ...customSectionLinks].map(
|
||||
(sectionLinkClass) => {
|
||||
return this.#initializeSectionLink(sectionLinkClass);
|
||||
}
|
||||
);
|
||||
}
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
|
||||
get moreSecondarySectionLinks() {
|
||||
return [
|
||||
this.moreSectionLinks = [
|
||||
...this.defaultMoreSectionLinks,
|
||||
...customSectionLinks,
|
||||
].map((sectionLinkClass) => {
|
||||
return this.#initializeSectionLink(sectionLinkClass);
|
||||
});
|
||||
|
||||
this.moreSecondarySectionLinks = [
|
||||
...this.defaultMoreSecondarySectionLinks,
|
||||
...secondaryCustomSectionLinks,
|
||||
].map((sectionLinkClass) => {
|
||||
return this.#initializeSectionLink(sectionLinkClass);
|
||||
});
|
||||
}
|
||||
|
||||
get mainSectionLinks() {
|
||||
return this.currentUser?.staff
|
||||
const mainSectionLinks = this.currentUser?.staff
|
||||
? [...this.defaultMainSectionLinks, ...this.defaultAdminMainSectionLinks]
|
||||
: [...this.defaultMainSectionLinks];
|
||||
}
|
||||
|
||||
get sectionLinks() {
|
||||
return this.mainSectionLinks.map((sectionLinkClass) => {
|
||||
this.sectionLinks = mainSectionLinks.map((sectionLinkClass) => {
|
||||
return this.#initializeSectionLink(sectionLinkClass);
|
||||
});
|
||||
|
||||
this.callbackId = this.topicTrackingState.onStateChange(() => {
|
||||
this.sectionLinks.forEach((sectionLink) => {
|
||||
sectionLink.onTopicTrackingStateChange();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
willDestroy() {
|
||||
this.sectionLinks.forEach((sectionLink) => sectionLink.teardown());
|
||||
this.topicTrackingState.offStateChange(this.callbackId);
|
||||
}
|
||||
|
||||
// Override in child
|
||||
get defaultMainSectionLinks() {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Override in child
|
||||
get defaultAdminMainSectionLinks() {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Override in child
|
||||
get defaultMoreSectionLinks() {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Override in child
|
||||
get defaultMoreSecondarySectionLinks() {
|
||||
return [];
|
||||
}
|
||||
|
||||
#initializeSectionLink(sectionLinkClass) {
|
||||
|
@ -21,22 +21,6 @@ export default class SidebarUserCommunitySection extends SidebarCommonCommunityS
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
|
||||
this.defaultMoreSectionLinks = [
|
||||
GroupsSectionLink,
|
||||
UsersSectionLink,
|
||||
BadgesSectionLink,
|
||||
];
|
||||
|
||||
this.defaultMoreSecondarySectionLinks = [AboutSectionLink, FAQSectionLink];
|
||||
|
||||
this.defaultMainSectionLinks = [
|
||||
EverythingSectionLink,
|
||||
TrackedSectionLink,
|
||||
MyPostsSectionLink,
|
||||
];
|
||||
|
||||
this.defaultAdminMainSectionLinks = [AdminSectionLink];
|
||||
|
||||
this.headerActionsIcon = "plus";
|
||||
|
||||
this.headerActions = [
|
||||
@ -47,6 +31,22 @@ export default class SidebarUserCommunitySection extends SidebarCommonCommunityS
|
||||
];
|
||||
}
|
||||
|
||||
get defaultMainSectionLinks() {
|
||||
return [EverythingSectionLink, TrackedSectionLink, MyPostsSectionLink];
|
||||
}
|
||||
|
||||
get defaultAdminMainSectionLinks() {
|
||||
return [AdminSectionLink];
|
||||
}
|
||||
|
||||
get defaultMoreSectionLinks() {
|
||||
return [GroupsSectionLink, UsersSectionLink, BadgesSectionLink];
|
||||
}
|
||||
|
||||
get defaultMoreSecondarySectionLinks() {
|
||||
return [AboutSectionLink, FAQSectionLink];
|
||||
}
|
||||
|
||||
@action
|
||||
composeTopic() {
|
||||
const composerArgs = {
|
||||
|
@ -16,6 +16,11 @@ export default class BaseCommunitySectionLink {
|
||||
this.siteSettings = siteSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when state has changed in the TopicTrackingState service
|
||||
*/
|
||||
onTopicTrackingStateChange() {}
|
||||
|
||||
/**
|
||||
* Called when community-section component is torn down.
|
||||
*/
|
||||
|
@ -1,34 +1,26 @@
|
||||
import I18n from "I18n";
|
||||
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { bind } from "discourse-common/utils/decorators";
|
||||
import BaseSectionLink from "discourse/lib/sidebar/base-community-section-link";
|
||||
|
||||
export default class EverythingSectionLink extends BaseSectionLink {
|
||||
@tracked totalUnread = 0;
|
||||
@tracked totalNew = 0;
|
||||
callbackId = null;
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
|
||||
if (this.currentUser) {
|
||||
this.callbackId = this.topicTrackingState.onStateChange(
|
||||
this._refreshCounts
|
||||
);
|
||||
|
||||
this._refreshCounts();
|
||||
}
|
||||
this.#refreshCounts();
|
||||
}
|
||||
|
||||
teardown() {
|
||||
if (this.callbackId) {
|
||||
this.topicTrackingState.offStateChange(this.callbackId);
|
||||
}
|
||||
onTopicTrackingStateChange() {
|
||||
this.#refreshCounts();
|
||||
}
|
||||
|
||||
@bind
|
||||
_refreshCounts() {
|
||||
#refreshCounts() {
|
||||
if (!this.currentUser) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.totalUnread = this.topicTrackingState.countUnread();
|
||||
|
||||
if (this.totalUnread === 0) {
|
||||
|
@ -1,30 +1,23 @@
|
||||
import I18n from "I18n";
|
||||
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { bind } from "discourse-common/utils/decorators";
|
||||
import BaseSectionLink from "discourse/lib/sidebar/base-community-section-link";
|
||||
import { isTrackedTopic } from "discourse/lib/topic-list-tracked-filter";
|
||||
|
||||
export default class TrackedSectionLink extends BaseSectionLink {
|
||||
@tracked totalUnread = 0;
|
||||
@tracked totalNew = 0;
|
||||
callbackId = null;
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
|
||||
this.callbackId = this.topicTrackingState.onStateChange(
|
||||
this._refreshCounts
|
||||
);
|
||||
this._refreshCounts();
|
||||
this.#refreshCounts();
|
||||
}
|
||||
|
||||
teardown() {
|
||||
this.topicTrackingState.offStateChange(this.callbackId);
|
||||
onTopicTrackingStateChange() {
|
||||
this.#refreshCounts();
|
||||
}
|
||||
|
||||
@bind
|
||||
_refreshCounts() {
|
||||
#refreshCounts() {
|
||||
this.totalUnread = this.topicTrackingState.countUnread({
|
||||
customFilterFn: isTrackedTopic,
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user