mirror of
https://github.com/discourse/discourse.git
synced 2024-12-21 18:03:43 +08:00
d4d939bd66
Using Ember's `<template>` dynamically is not supported. For every invocation, glimmer-vm has to run one-time setup, and will cache the result indefinitely. This leads to significant memory leaks, and eventual OOM errors. This commit updates a handful of cases. We'll be following up with the more complex ones, and a linting rule to avoid re-introducing the problem in future.
136 lines
4.2 KiB
Plaintext
136 lines
4.2 KiB
Plaintext
import Component from "@glimmer/component";
|
|
import { tracked } from "@glimmer/tracking";
|
|
import { hash } from "@ember/helper";
|
|
import { action } from "@ember/object";
|
|
import { service } from "@ember/service";
|
|
import { htmlSafe } from "@ember/template";
|
|
import { isEmpty } from "@ember/utils";
|
|
import { NotificationLevels } from "discourse/lib/notification-levels";
|
|
import getURL from "discourse-common/lib/get-url";
|
|
import I18n, { i18n } from "discourse-i18n";
|
|
import TopicNotificationsOptions from "select-kit/components/topic-notifications-options";
|
|
|
|
const ParagraphWrapper = <template><p class="reason">{{yield}}</p></template>;
|
|
const EmptyWrapper = <template>
|
|
{{! template-lint-disable no-yield-only}}{{yield}}
|
|
</template>;
|
|
|
|
export default class TopicNotificationsButton extends Component {
|
|
@service currentUser;
|
|
|
|
@tracked isLoading = false;
|
|
|
|
get notificationLevel() {
|
|
return this.args.topic.get("details.notification_level");
|
|
}
|
|
|
|
get reasonText() {
|
|
const topic = this.args.topic;
|
|
const level = topic.get("details.notification_level") ?? 1;
|
|
const reason = topic.get("details.notifications_reason_id");
|
|
let localeString = `topic.notifications.reasons.${level}`;
|
|
|
|
if (typeof reason === "number") {
|
|
let localeStringWithReason = `${localeString}_${reason}`;
|
|
|
|
if (this._reasonStale(level, reason)) {
|
|
localeStringWithReason += "_stale";
|
|
}
|
|
|
|
// some sane protection for missing translations of edge cases
|
|
if (I18n.lookup(localeStringWithReason, { locale: "en" })) {
|
|
localeString = localeStringWithReason;
|
|
}
|
|
}
|
|
|
|
if (
|
|
this.currentUser?.user_option.mailing_list_mode &&
|
|
level > NotificationLevels.MUTED
|
|
) {
|
|
return i18n("topic.notifications.reasons.mailing_list_mode");
|
|
} else {
|
|
return i18n(localeString, {
|
|
username: this.currentUser?.username_lower,
|
|
basePath: getURL(""),
|
|
});
|
|
}
|
|
}
|
|
|
|
// The user may have changed their category or tag tracking settings
|
|
// since this topic was tracked/watched based on those settings in the
|
|
// past. In that case we need to alter the reason message we show them
|
|
// otherwise it is very confusing for the end user to be told they are
|
|
// tracking a topic because of a category, when they are no longer tracking
|
|
// that category.
|
|
_reasonStale(level, reason) {
|
|
if (!this.currentUser) {
|
|
return;
|
|
}
|
|
|
|
const watchedCategoryIds = this.currentUser.watched_category_ids || [];
|
|
const trackedCategoryIds = this.currentUser.tracked_category_ids || [];
|
|
const watchedTags = this.currentUser.watched_tags || [];
|
|
|
|
if (this.args.topic.category_id) {
|
|
if (level === 2 && reason === 8) {
|
|
// 2_8 tracking category
|
|
return !trackedCategoryIds.includes(this.args.topic.category_id);
|
|
} else if (level === 3 && reason === 6) {
|
|
// 3_6 watching category
|
|
return !watchedCategoryIds.includes(this.args.topic.category_id);
|
|
}
|
|
} else if (!isEmpty(this.args.topic.tags)) {
|
|
if (level === 3 && reason === 10) {
|
|
// 3_10 watching tag
|
|
return !this.args.topic.tags.some((tag) => watchedTags.includes(tag));
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
get conditionalWrapper() {
|
|
if (this.args.expanded) {
|
|
return ParagraphWrapper;
|
|
} else {
|
|
return EmptyWrapper;
|
|
}
|
|
}
|
|
|
|
@action
|
|
async changeTopicNotificationLevel(levelId) {
|
|
if (levelId === this.notificationLevel) {
|
|
return;
|
|
}
|
|
|
|
this.isLoading = true;
|
|
|
|
try {
|
|
await this.args.topic.details.updateNotifications(levelId);
|
|
} finally {
|
|
this.isLoading = false;
|
|
}
|
|
}
|
|
|
|
<template>
|
|
<div class="topic-notifications-button" ...attributes>
|
|
<this.conditionalWrapper>
|
|
<TopicNotificationsOptions
|
|
@value={{this.notificationLevel}}
|
|
@topic={{@topic}}
|
|
@onChange={{this.changeTopicNotificationLevel}}
|
|
@options={{hash
|
|
icon=(if this.isLoading "spinner")
|
|
showFullTitle=@expanded
|
|
showCaret=@expanded
|
|
headerAriaLabel=(i18n "topic.notifications.title")
|
|
}}
|
|
/>
|
|
{{#if @expanded}}
|
|
<span class="text">{{htmlSafe this.reasonText}}</span>
|
|
{{/if}}
|
|
</this.conditionalWrapper>
|
|
</div>
|
|
</template>
|
|
}
|