mirror of
https://github.com/discourse/discourse.git
synced 2025-03-24 07:21:48 +08:00
DEV: Clean up all message bus subscriptions (#19268)
1. "What Goes Up Must Come Down" – if you subscribe to message bus, make sure you also unsubscribe 2. When you unsubscribe - remove only your subscription, not **all** subscriptions on given channel Attempt #2. The first attempt tried to extend a core `@bound` method in new-user-narrative plugin which did not work. I reworked that plugin in the meantime. This new PR also cleans up message bus subscriptions in now core-merged chat plugin.
This commit is contained in:
parent
93a4012ecb
commit
19214aff18
app/assets/javascripts
admin/addon
controllers
routes
discourse/app
components
controllers
initializers
banner.jslive-development.jslogout.jsread-only.jssubscribe-user-notifications.jsuser-tips.jswelcome-topic-banner.js
models
pre-initializers
routes
services
plugins
chat/assets/javascripts/discourse
components
services
discourse-narrative-bot/assets/javascripts/initializers
poll/assets/javascripts/initializers
@ -2,7 +2,7 @@ import Controller from "@ember/controller";
|
|||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import { alias } from "@ember/object/computed";
|
import { alias } from "@ember/object/computed";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed, { bind } from "discourse-common/utils/decorators";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default Controller.extend({
|
||||||
@ -23,24 +23,22 @@ export default Controller.extend({
|
|||||||
subscribe() {
|
subscribe() {
|
||||||
this.messageBus.subscribe(
|
this.messageBus.subscribe(
|
||||||
`/web_hook_events/${this.get("model.extras.web_hook_id")}`,
|
`/web_hook_events/${this.get("model.extras.web_hook_id")}`,
|
||||||
(data) => {
|
this._addIncoming
|
||||||
if (data.event_type === "ping") {
|
|
||||||
this.set("pingDisabled", false);
|
|
||||||
}
|
|
||||||
this._addIncoming(data.web_hook_event_id);
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
unsubscribe() {
|
unsubscribe() {
|
||||||
this.messageBus.unsubscribe("/web_hook_events/*");
|
this.messageBus.unsubscribe("/web_hook_events/*", this._addIncoming);
|
||||||
},
|
},
|
||||||
|
|
||||||
_addIncoming(eventId) {
|
@bind
|
||||||
const incomingEventIds = this.incomingEventIds;
|
_addIncoming(data) {
|
||||||
|
if (data.event_type === "ping") {
|
||||||
|
this.set("pingDisabled", false);
|
||||||
|
}
|
||||||
|
|
||||||
if (!incomingEventIds.includes(eventId)) {
|
if (!this.incomingEventIds.includes(data.web_hook_event_id)) {
|
||||||
incomingEventIds.pushObject(eventId);
|
this.incomingEventIds.pushObject(data.web_hook_event_id);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -2,13 +2,21 @@ import Controller from "@ember/controller";
|
|||||||
import DiscourseURL from "discourse/lib/url";
|
import DiscourseURL from "discourse/lib/url";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||||
import messageBus from "message-bus-client";
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default Controller.extend(ModalFunctionality, {
|
export default Controller.extend(ModalFunctionality, {
|
||||||
message: I18n.t("admin.user.merging_user"),
|
message: I18n.t("admin.user.merging_user"),
|
||||||
|
|
||||||
onShow() {
|
onShow() {
|
||||||
messageBus.subscribe("/merge_user", (data) => {
|
this.messageBus.subscribe("/merge_user", this.onMessage);
|
||||||
|
},
|
||||||
|
|
||||||
|
onClose() {
|
||||||
|
this.messageBus.unsubscribe("/merge_user", this.onMessage);
|
||||||
|
},
|
||||||
|
|
||||||
|
@bind
|
||||||
|
onMessage(data) {
|
||||||
if (data.merged) {
|
if (data.merged) {
|
||||||
if (/^\/admin\/users\/list\//.test(location)) {
|
if (/^\/admin\/users\/list\//.test(location)) {
|
||||||
DiscourseURL.redirectTo(location);
|
DiscourseURL.redirectTo(location);
|
||||||
@ -22,10 +30,5 @@ export default Controller.extend(ModalFunctionality, {
|
|||||||
} else if (data.failed) {
|
} else if (data.failed) {
|
||||||
this.set("message", I18n.t("admin.user.merge_failed"));
|
this.set("message", I18n.t("admin.user.merge_failed"));
|
||||||
}
|
}
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
onClose() {
|
|
||||||
this.messageBus.unsubscribe("/merge_user");
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import Backup from "admin/models/backup";
|
import Backup from "admin/models/backup";
|
||||||
import Route from "@ember/routing/route";
|
import Route from "@ember/routing/route";
|
||||||
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default Route.extend({
|
export default Route.extend({
|
||||||
activate() {
|
activate() {
|
||||||
this.messageBus.subscribe("/admin/backups", (backups) =>
|
this.messageBus.subscribe("/admin/backups", this.onMessage);
|
||||||
this.controller.set(
|
},
|
||||||
"model",
|
|
||||||
backups.map((backup) => Backup.create(backup))
|
deactivate() {
|
||||||
)
|
this.messageBus.unsubscribe("/admin/backups", this.onMessage);
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
model() {
|
model() {
|
||||||
@ -17,7 +17,11 @@ export default Route.extend({
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
deactivate() {
|
@bind
|
||||||
this.messageBus.unsubscribe("/admin/backups");
|
onMessage(backups) {
|
||||||
|
this.controller.set(
|
||||||
|
"model",
|
||||||
|
backups.map((backup) => Backup.create(backup))
|
||||||
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -10,46 +10,19 @@ import { extractError } from "discourse/lib/ajax-error";
|
|||||||
import getURL from "discourse-common/lib/get-url";
|
import getURL from "discourse-common/lib/get-url";
|
||||||
import showModal from "discourse/lib/show-modal";
|
import showModal from "discourse/lib/show-modal";
|
||||||
import { inject as service } from "@ember/service";
|
import { inject as service } from "@ember/service";
|
||||||
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
const LOG_CHANNEL = "/admin/backups/logs";
|
const LOG_CHANNEL = "/admin/backups/logs";
|
||||||
|
|
||||||
export default DiscourseRoute.extend({
|
export default DiscourseRoute.extend({
|
||||||
dialog: service(),
|
dialog: service(),
|
||||||
|
|
||||||
activate() {
|
activate() {
|
||||||
this.messageBus.subscribe(LOG_CHANNEL, (log) => {
|
this.messageBus.subscribe(LOG_CHANNEL, this.onMessage);
|
||||||
if (log.message === "[STARTED]") {
|
},
|
||||||
User.currentProp("hideReadOnlyAlert", true);
|
|
||||||
this.controllerFor("adminBackups").set(
|
deactivate() {
|
||||||
"model.isOperationRunning",
|
this.messageBus.unsubscribe(LOG_CHANNEL, this.onMessage);
|
||||||
true
|
|
||||||
);
|
|
||||||
this.controllerFor("adminBackupsLogs").get("logs").clear();
|
|
||||||
} else if (log.message === "[FAILED]") {
|
|
||||||
this.controllerFor("adminBackups").set(
|
|
||||||
"model.isOperationRunning",
|
|
||||||
false
|
|
||||||
);
|
|
||||||
this.dialog.alert(
|
|
||||||
I18n.t("admin.backups.operations.failed", {
|
|
||||||
operation: log.operation,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
} else if (log.message === "[SUCCESS]") {
|
|
||||||
User.currentProp("hideReadOnlyAlert", false);
|
|
||||||
this.controllerFor("adminBackups").set(
|
|
||||||
"model.isOperationRunning",
|
|
||||||
false
|
|
||||||
);
|
|
||||||
if (log.operation === "restore") {
|
|
||||||
// redirect to homepage when the restore is done (session might be lost)
|
|
||||||
window.location = getURL("/");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.controllerFor("adminBackupsLogs")
|
|
||||||
.get("logs")
|
|
||||||
.pushObject(EmberObject.create(log));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
model() {
|
model() {
|
||||||
@ -64,8 +37,31 @@ export default DiscourseRoute.extend({
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
deactivate() {
|
@bind
|
||||||
this.messageBus.unsubscribe(LOG_CHANNEL);
|
onMessage(log) {
|
||||||
|
if (log.message === "[STARTED]") {
|
||||||
|
User.currentProp("hideReadOnlyAlert", true);
|
||||||
|
this.controllerFor("adminBackups").set("model.isOperationRunning", true);
|
||||||
|
this.controllerFor("adminBackupsLogs").get("logs").clear();
|
||||||
|
} else if (log.message === "[FAILED]") {
|
||||||
|
this.controllerFor("adminBackups").set("model.isOperationRunning", false);
|
||||||
|
this.dialog.alert(
|
||||||
|
I18n.t("admin.backups.operations.failed", {
|
||||||
|
operation: log.operation,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else if (log.message === "[SUCCESS]") {
|
||||||
|
User.currentProp("hideReadOnlyAlert", false);
|
||||||
|
this.controllerFor("adminBackups").set("model.isOperationRunning", false);
|
||||||
|
if (log.operation === "restore") {
|
||||||
|
// redirect to homepage when the restore is done (session might be lost)
|
||||||
|
window.location = getURL("/");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.controllerFor("adminBackupsLogs")
|
||||||
|
.get("logs")
|
||||||
|
.pushObject(EmberObject.create(log));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
import { alias, not } from "@ember/object/computed";
|
import { alias, not } from "@ember/object/computed";
|
||||||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
import discourseComputed, {
|
||||||
|
bind,
|
||||||
|
observes,
|
||||||
|
} from "discourse-common/utils/decorators";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
@ -40,18 +43,11 @@ export default Component.extend({
|
|||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
|
||||||
this.topics.forEach((topic) => {
|
this.topics.forEach((topic) => {
|
||||||
const includeUnreadIndicator =
|
if (typeof topic.unread_by_group_member !== "undefined") {
|
||||||
typeof topic.unread_by_group_member !== "undefined";
|
this.messageBus.subscribe(
|
||||||
|
`/private-messages/unread-indicator/${topic.id}`,
|
||||||
if (includeUnreadIndicator) {
|
this.onMessage
|
||||||
const unreadIndicatorChannel = `/private-messages/unread-indicator/${topic.id}`;
|
);
|
||||||
this.messageBus.subscribe(unreadIndicatorChannel, (data) => {
|
|
||||||
const nodeClassList = document.querySelector(
|
|
||||||
`.indicator-topic-${data.topic_id}`
|
|
||||||
).classList;
|
|
||||||
|
|
||||||
nodeClassList.toggle("read", !data.show_indicator);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -59,15 +55,19 @@ export default Component.extend({
|
|||||||
willDestroyElement() {
|
willDestroyElement() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
|
||||||
this.topics.forEach((topic) => {
|
this.messageBus.unsubscribe(
|
||||||
const includeUnreadIndicator =
|
"/private-messages/unread-indicator/*",
|
||||||
typeof topic.unread_by_group_member !== "undefined";
|
this.onMessage
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
if (includeUnreadIndicator) {
|
@bind
|
||||||
const unreadIndicatorChannel = `/private-messages/unread-indicator/${topic.id}`;
|
onMessage(data) {
|
||||||
this.messageBus.unsubscribe(unreadIndicatorChannel);
|
const nodeClassList = document.querySelector(
|
||||||
}
|
`.indicator-topic-${data.topic_id}`
|
||||||
});
|
).classList;
|
||||||
|
|
||||||
|
nodeClassList.toggle("read", !data.show_indicator);
|
||||||
},
|
},
|
||||||
|
|
||||||
@discourseComputed("topics")
|
@discourseComputed("topics")
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import getURL from "discourse-common/lib/get-url";
|
import getURL from "discourse-common/lib/get-url";
|
||||||
import { cancel } from "@ember/runloop";
|
import { cancel } from "@ember/runloop";
|
||||||
import discourseLater from "discourse-common/lib/later";
|
import discourseLater from "discourse-common/lib/later";
|
||||||
import discourseComputed, { on } from "discourse-common/utils/decorators";
|
import discourseComputed, { bind, on } from "discourse-common/utils/decorators";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import { isTesting } from "discourse-common/config/environment";
|
import { isTesting } from "discourse-common/config/environment";
|
||||||
@ -13,18 +13,27 @@ export default Component.extend({
|
|||||||
animatePrompt: false,
|
animatePrompt: false,
|
||||||
_timeoutHandler: null,
|
_timeoutHandler: null,
|
||||||
|
|
||||||
@discourseComputed
|
init() {
|
||||||
rootUrl() {
|
this._super(...arguments);
|
||||||
return getURL("/");
|
|
||||||
|
this.messageBus.subscribe("/refresh_client", this.onRefresh);
|
||||||
|
this.messageBus.subscribe("/global/asset-version", this.onAsset);
|
||||||
},
|
},
|
||||||
|
|
||||||
@on("init")
|
willDestroy() {
|
||||||
initSubscriptions() {
|
this._super(...arguments);
|
||||||
this.messageBus.subscribe("/refresh_client", () => {
|
|
||||||
this.session.requiresRefresh = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.messageBus.subscribe("/global/asset-version", (version) => {
|
this.messageBus.unsubscribe("/refresh_client", this.onRefresh);
|
||||||
|
this.messageBus.unsubscribe("/global/asset-version", this.onAsset);
|
||||||
|
},
|
||||||
|
|
||||||
|
@bind
|
||||||
|
onRefresh() {
|
||||||
|
this.session.requiresRefresh = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
@bind
|
||||||
|
onAsset(version) {
|
||||||
if (this.session.assetVersion !== version) {
|
if (this.session.assetVersion !== version) {
|
||||||
this.session.requiresRefresh = true;
|
this.session.requiresRefresh = true;
|
||||||
}
|
}
|
||||||
@ -40,7 +49,11 @@ export default Component.extend({
|
|||||||
}, 1000 * 60 * 24 * 60);
|
}, 1000 * 60 * 24 * 60);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
|
||||||
|
@discourseComputed
|
||||||
|
rootUrl() {
|
||||||
|
return getURL("/");
|
||||||
},
|
},
|
||||||
|
|
||||||
updatePromptState(value) {
|
updatePromptState(value) {
|
||||||
|
@ -77,13 +77,7 @@ export default Component.extend({
|
|||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
|
||||||
if (this.includeUnreadIndicator) {
|
if (this.includeUnreadIndicator) {
|
||||||
this.messageBus.subscribe(this.unreadIndicatorChannel, (data) => {
|
this.messageBus.subscribe(this.unreadIndicatorChannel, this.onMessage);
|
||||||
const nodeClassList = document.querySelector(
|
|
||||||
`.indicator-topic-${data.topic_id}`
|
|
||||||
).classList;
|
|
||||||
|
|
||||||
nodeClassList.toggle("read", !data.show_indicator);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
schedule("afterRender", () => {
|
schedule("afterRender", () => {
|
||||||
@ -101,9 +95,8 @@ export default Component.extend({
|
|||||||
willDestroyElement() {
|
willDestroyElement() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
|
||||||
if (this.includeUnreadIndicator) {
|
this.messageBus.unsubscribe(this.unreadIndicatorChannel, this.onMessage);
|
||||||
this.messageBus.unsubscribe(this.unreadIndicatorChannel);
|
|
||||||
}
|
|
||||||
if (this._shouldFocusLastVisited()) {
|
if (this._shouldFocusLastVisited()) {
|
||||||
const title = this._titleElement();
|
const title = this._titleElement();
|
||||||
if (title) {
|
if (title) {
|
||||||
@ -113,6 +106,15 @@ export default Component.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@bind
|
||||||
|
onMessage(data) {
|
||||||
|
const nodeClassList = document.querySelector(
|
||||||
|
`.indicator-topic-${data.topic_id}`
|
||||||
|
).classList;
|
||||||
|
|
||||||
|
nodeClassList.toggle("read", !data.show_indicator);
|
||||||
|
},
|
||||||
|
|
||||||
@discourseComputed("topic.id")
|
@discourseComputed("topic.id")
|
||||||
unreadIndicatorChannel(topicId) {
|
unreadIndicatorChannel(topicId) {
|
||||||
return `/private-messages/unread-indicator/${topicId}`;
|
return `/private-messages/unread-indicator/${topicId}`;
|
||||||
|
@ -2,7 +2,10 @@ import Category from "discourse/models/category";
|
|||||||
import Controller, { inject as controller } from "@ember/controller";
|
import Controller, { inject as controller } from "@ember/controller";
|
||||||
import DiscourseURL, { userPath } from "discourse/lib/url";
|
import DiscourseURL, { userPath } from "discourse/lib/url";
|
||||||
import { alias, and, not, or } from "@ember/object/computed";
|
import { alias, and, not, or } from "@ember/object/computed";
|
||||||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
import discourseComputed, {
|
||||||
|
bind,
|
||||||
|
observes,
|
||||||
|
} from "discourse-common/utils/decorators";
|
||||||
import { isEmpty, isPresent } from "@ember/utils";
|
import { isEmpty, isPresent } from "@ember/utils";
|
||||||
import { next, schedule } from "@ember/runloop";
|
import { next, schedule } from "@ember/runloop";
|
||||||
import discourseLater from "discourse-common/lib/later";
|
import discourseLater from "discourse-common/lib/later";
|
||||||
@ -1599,19 +1602,30 @@ export default Controller.extend(bufferedProperty("model"), {
|
|||||||
subscribe() {
|
subscribe() {
|
||||||
this.unsubscribe();
|
this.unsubscribe();
|
||||||
|
|
||||||
|
this.messageBus.subscribe(
|
||||||
|
`/topic/${this.get("model.id")}`,
|
||||||
|
this.onMessage,
|
||||||
|
this.get("model.message_bus_last_id")
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
unsubscribe() {
|
||||||
|
// never unsubscribe when navigating from topic to topic
|
||||||
|
if (!this.get("model.id")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.messageBus.unsubscribe("/topic/*", this.onMessage);
|
||||||
|
},
|
||||||
|
|
||||||
|
@bind
|
||||||
|
onMessage(data) {
|
||||||
|
const topic = this.model;
|
||||||
const refresh = (args) =>
|
const refresh = (args) =>
|
||||||
this.appEvents.trigger("post-stream:refresh", args);
|
this.appEvents.trigger("post-stream:refresh", args);
|
||||||
|
|
||||||
this.messageBus.subscribe(
|
|
||||||
`/topic/${this.get("model.id")}`,
|
|
||||||
(data) => {
|
|
||||||
const topic = this.model;
|
|
||||||
|
|
||||||
if (isPresent(data.notification_level_change)) {
|
if (isPresent(data.notification_level_change)) {
|
||||||
topic.set(
|
topic.set("details.notification_level", data.notification_level_change);
|
||||||
"details.notification_level",
|
|
||||||
data.notification_level_change
|
|
||||||
);
|
|
||||||
topic.set(
|
topic.set(
|
||||||
"details.notifications_reason_id",
|
"details.notifications_reason_id",
|
||||||
data.notifications_reason_id
|
data.notifications_reason_id
|
||||||
@ -1650,12 +1664,7 @@ export default Controller.extend(bufferedProperty("model"), {
|
|||||||
case "liked":
|
case "liked":
|
||||||
case "unliked": {
|
case "unliked": {
|
||||||
postStream
|
postStream
|
||||||
.triggerLikedPost(
|
.triggerLikedPost(data.id, data.likes_count, data.user_id, data.type)
|
||||||
data.id,
|
|
||||||
data.likes_count,
|
|
||||||
data.user_id,
|
|
||||||
data.type
|
|
||||||
)
|
|
||||||
.then(() => refresh({ id: data.id, refreshLikes: true }));
|
.then(() => refresh({ id: data.id, refreshLikes: true }));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1695,9 +1704,7 @@ export default Controller.extend(bufferedProperty("model"), {
|
|||||||
.triggerNewPostsInStream(postIds, { background: true })
|
.triggerNewPostsInStream(postIds, { background: true })
|
||||||
.then(() => refresh())
|
.then(() => refresh())
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
this._newPostsInStream = postIds.concat(
|
this._newPostsInStream = postIds.concat(this._newPostsInStream);
|
||||||
this._newPostsInStream
|
|
||||||
);
|
|
||||||
throw e;
|
throw e;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -1717,15 +1724,13 @@ export default Controller.extend(bufferedProperty("model"), {
|
|||||||
}
|
}
|
||||||
case "stats": {
|
case "stats": {
|
||||||
let updateStream = false;
|
let updateStream = false;
|
||||||
["last_posted_at", "like_count", "posts_count"].forEach(
|
["last_posted_at", "like_count", "posts_count"].forEach((property) => {
|
||||||
(property) => {
|
|
||||||
const value = data[property];
|
const value = data[property];
|
||||||
if (typeof value !== "undefined") {
|
if (typeof value !== "undefined") {
|
||||||
topic.set(property, value);
|
topic.set(property, value);
|
||||||
updateStream = true;
|
updateStream = true;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
if (data["last_poster"]) {
|
if (data["last_poster"]) {
|
||||||
topic.details.set("last_poster", data["last_poster"]);
|
topic.details.set("last_poster", data["last_poster"]);
|
||||||
@ -1750,17 +1755,6 @@ export default Controller.extend(bufferedProperty("model"), {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
this.get("model.message_bus_last_id")
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
unsubscribe() {
|
|
||||||
// never unsubscribe when navigating from topic to topic
|
|
||||||
if (!this.get("model.id")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.messageBus.unsubscribe("/topic/*");
|
|
||||||
},
|
|
||||||
|
|
||||||
reply() {
|
reply() {
|
||||||
this.replyToPost();
|
this.replyToPost();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import EmberObject from "@ember/object";
|
import EmberObject from "@ember/object";
|
||||||
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
import PreloadStore from "discourse/lib/preload-store";
|
import PreloadStore from "discourse/lib/preload-store";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -6,14 +7,21 @@ export default {
|
|||||||
after: "message-bus",
|
after: "message-bus",
|
||||||
|
|
||||||
initialize(container) {
|
initialize(container) {
|
||||||
const site = container.lookup("service:site");
|
this.site = container.lookup("service:site");
|
||||||
|
this.messageBus = container.lookup("service:message-bus");
|
||||||
|
|
||||||
const banner = EmberObject.create(PreloadStore.get("banner") || {});
|
const banner = EmberObject.create(PreloadStore.get("banner") || {});
|
||||||
const messageBus = container.lookup("service:message-bus");
|
this.site.set("banner", banner);
|
||||||
|
|
||||||
site.set("banner", banner);
|
this.messageBus.subscribe("/site/banner", this.onMessage);
|
||||||
|
},
|
||||||
|
|
||||||
messageBus.subscribe("/site/banner", (data) => {
|
teardown() {
|
||||||
site.set("banner", EmberObject.create(data || {}));
|
this.messageBus.unsubscribe("/site/banner", this.onMessage);
|
||||||
});
|
},
|
||||||
|
|
||||||
|
@bind
|
||||||
|
onMessage(data = {}) {
|
||||||
|
this.site.set("banner", EmberObject.create(data));
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
import DiscourseURL from "discourse/lib/url";
|
import DiscourseURL from "discourse/lib/url";
|
||||||
import { isDevelopment } from "discourse-common/config/environment";
|
import { isDevelopment } from "discourse-common/config/environment";
|
||||||
import discourseLater from "discourse-common/lib/later";
|
import discourseLater from "discourse-common/lib/later";
|
||||||
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
// Use the message bus for live reloading of components for faster development.
|
// Use the message bus for live reloading of components for faster development.
|
||||||
export default {
|
export default {
|
||||||
name: "live-development",
|
name: "live-development",
|
||||||
|
|
||||||
initialize(container) {
|
initialize(container) {
|
||||||
const messageBus = container.lookup("service:message-bus");
|
this.messageBus = container.lookup("service:message-bus");
|
||||||
const session = container.lookup("service:session");
|
const session = container.lookup("service:session");
|
||||||
|
|
||||||
// Preserve preview_theme_id=## and pp=async-flamegraph parameters across pages
|
// Preserve preview_theme_id=## and pp=async-flamegraph parameters across pages
|
||||||
@ -38,36 +39,45 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Observe file changes
|
// Observe file changes
|
||||||
messageBus.subscribe(
|
this.messageBus.subscribe(
|
||||||
"/file-change",
|
"/file-change",
|
||||||
(data) => {
|
this.onFileChange,
|
||||||
|
session.mbLastFileChangeId
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
teardown() {
|
||||||
|
this.messageBus.unsubscribe("/file-change", this.onFileChange);
|
||||||
|
},
|
||||||
|
|
||||||
|
@bind
|
||||||
|
onFileChange(data) {
|
||||||
data.forEach((me) => {
|
data.forEach((me) => {
|
||||||
if (me === "refresh") {
|
if (me === "refresh") {
|
||||||
// Refresh if necessary
|
// Refresh if necessary
|
||||||
document.location.reload(true);
|
document.location.reload(true);
|
||||||
} else if (me.new_href && me.target) {
|
} else if (me.new_href && me.target) {
|
||||||
const link_target = !!me.theme_id
|
let query = `link[data-target='${me.target}']`;
|
||||||
? `[data-target='${me.target}'][data-theme-id='${me.theme_id}']`
|
|
||||||
: `[data-target='${me.target}']`;
|
if (me.theme_id) {
|
||||||
|
query += `[data-theme-id='${me.theme_id}']`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const links = document.querySelectorAll(query);
|
||||||
|
|
||||||
const links = document.querySelectorAll(`link${link_target}`);
|
|
||||||
if (links.length > 0) {
|
if (links.length > 0) {
|
||||||
const lastLink = links[links.length - 1];
|
const lastLink = links[links.length - 1];
|
||||||
|
|
||||||
// this check is useful when message-bus has multiple file updates
|
// this check is useful when message-bus has multiple file updates
|
||||||
// it avoids the browser doing a lot of work for nothing
|
// it avoids the browser doing a lot of work for nothing
|
||||||
// should the filenames be unchanged
|
// should the filenames be unchanged
|
||||||
if (
|
if (lastLink.href.split("/").pop() !== me.new_href.split("/").pop()) {
|
||||||
lastLink.href.split("/").pop() !== me.new_href.split("/").pop()
|
|
||||||
) {
|
|
||||||
this.refreshCSS(lastLink, me.new_href);
|
this.refreshCSS(lastLink, me.new_href);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
session.mbLastFileChangeId
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
refreshCSS(node, newHref) {
|
refreshCSS(node, newHref) {
|
||||||
const reloaded = node.cloneNode(true);
|
const reloaded = node.cloneNode(true);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import logout from "discourse/lib/logout";
|
import logout from "discourse/lib/logout";
|
||||||
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
let _showingLogout = false;
|
let _showingLogout = false;
|
||||||
|
|
||||||
@ -9,27 +10,30 @@ export default {
|
|||||||
after: "message-bus",
|
after: "message-bus",
|
||||||
|
|
||||||
initialize(container) {
|
initialize(container) {
|
||||||
const messageBus = container.lookup("service:message-bus"),
|
this.messageBus = container.lookup("service:message-bus");
|
||||||
dialog = container.lookup("service:dialog");
|
this.dialog = container.lookup("service:dialog");
|
||||||
|
|
||||||
if (!messageBus) {
|
this.messageBus.subscribe("/logout", this.onMessage);
|
||||||
|
},
|
||||||
|
|
||||||
|
teardown() {
|
||||||
|
this.messageBus.unsubscribe("/logout", this.onMessage);
|
||||||
|
},
|
||||||
|
|
||||||
|
@bind
|
||||||
|
onMessage() {
|
||||||
|
if (_showingLogout) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
messageBus.subscribe("/logout", function () {
|
|
||||||
if (!_showingLogout) {
|
|
||||||
_showingLogout = true;
|
_showingLogout = true;
|
||||||
|
|
||||||
dialog.alert({
|
this.dialog.alert({
|
||||||
message: I18n.t("logout"),
|
message: I18n.t("logout"),
|
||||||
confirmButtonLabel: "home",
|
confirmButtonLabel: "home",
|
||||||
didConfirm: logout,
|
didConfirm: logout,
|
||||||
didCancel: logout,
|
didCancel: logout,
|
||||||
shouldDisplayCancel: false,
|
shouldDisplayCancel: false,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
_showingLogout = true;
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,13 +1,23 @@
|
|||||||
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
// Subscribe to "read-only" status change events via the Message Bus
|
// Subscribe to "read-only" status change events via the Message Bus
|
||||||
export default {
|
export default {
|
||||||
name: "read-only",
|
name: "read-only",
|
||||||
after: "message-bus",
|
after: "message-bus",
|
||||||
|
|
||||||
initialize(container) {
|
initialize(container) {
|
||||||
const messageBus = container.lookup("service:message-bus");
|
this.messageBus = container.lookup("service:message-bus");
|
||||||
const site = container.lookup("service:site");
|
this.site = container.lookup("service:site");
|
||||||
messageBus.subscribe("/site/read-only", (enabled) => {
|
|
||||||
site.set("isReadOnly", enabled);
|
this.messageBus.subscribe("/site/read-only", this.onMessage);
|
||||||
});
|
},
|
||||||
|
|
||||||
|
teardown() {
|
||||||
|
this.messageBus.unsubscribe("/site/read-only", this.onMessage);
|
||||||
|
},
|
||||||
|
|
||||||
|
@bind
|
||||||
|
onMessage(enabled) {
|
||||||
|
this.site.set("isReadOnly", enabled);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -12,41 +12,131 @@ import {
|
|||||||
} from "discourse/lib/push-notifications";
|
} from "discourse/lib/push-notifications";
|
||||||
import { isTesting } from "discourse-common/config/environment";
|
import { isTesting } from "discourse-common/config/environment";
|
||||||
import Notification from "discourse/models/notification";
|
import Notification from "discourse/models/notification";
|
||||||
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "subscribe-user-notifications",
|
name: "subscribe-user-notifications",
|
||||||
after: "message-bus",
|
after: "message-bus",
|
||||||
|
|
||||||
initialize(container) {
|
initialize(container) {
|
||||||
const user = container.lookup("service:current-user");
|
this.currentUser = container.lookup("service:current-user");
|
||||||
const bus = container.lookup("service:message-bus");
|
|
||||||
const appEvents = container.lookup("service:app-events");
|
|
||||||
const siteSettings = container.lookup("service:site-settings");
|
|
||||||
|
|
||||||
if (user) {
|
if (!this.currentUser) {
|
||||||
const channel = user.redesigned_user_menu_enabled
|
return;
|
||||||
? `/reviewable_counts/${user.id}`
|
}
|
||||||
|
|
||||||
|
this.messageBus = container.lookup("service:message-bus");
|
||||||
|
this.store = container.lookup("service:store");
|
||||||
|
this.messageBus = container.lookup("service:message-bus");
|
||||||
|
this.appEvents = container.lookup("service:app-events");
|
||||||
|
this.siteSettings = container.lookup("service:site-settings");
|
||||||
|
this.site = container.lookup("service:site");
|
||||||
|
this.router = container.lookup("router:main");
|
||||||
|
|
||||||
|
this.reviewableCountsChannel = this.currentUser.redesigned_user_menu_enabled
|
||||||
|
? `/reviewable_counts/${this.currentUser.id}`
|
||||||
: "/reviewable_counts";
|
: "/reviewable_counts";
|
||||||
|
|
||||||
bus.subscribe(channel, (data) => {
|
this.messageBus.subscribe(
|
||||||
|
this.reviewableCountsChannel,
|
||||||
|
this.onReviewableCounts
|
||||||
|
);
|
||||||
|
|
||||||
|
this.messageBus.subscribe(
|
||||||
|
`/notification/${this.currentUser.id}`,
|
||||||
|
this.onNotification,
|
||||||
|
this.currentUser.notification_channel_position
|
||||||
|
);
|
||||||
|
|
||||||
|
this.messageBus.subscribe(
|
||||||
|
`/user-drafts/${this.currentUser.id}`,
|
||||||
|
this.onUserDrafts
|
||||||
|
);
|
||||||
|
|
||||||
|
this.messageBus.subscribe(
|
||||||
|
`/do-not-disturb/${this.currentUser.id}`,
|
||||||
|
this.onDoNotDisturb
|
||||||
|
);
|
||||||
|
|
||||||
|
this.messageBus.subscribe(`/user-status`, this.onUserStatus);
|
||||||
|
|
||||||
|
this.messageBus.subscribe("/categories", this.onCategories);
|
||||||
|
|
||||||
|
this.messageBus.subscribe("/client_settings", this.onClientSettings);
|
||||||
|
|
||||||
|
if (!isTesting()) {
|
||||||
|
this.messageBus.subscribe(alertChannel(this.currentUser), this.onAlert);
|
||||||
|
|
||||||
|
initDesktopNotifications(this.messageBus, this.appEvents);
|
||||||
|
|
||||||
|
if (isPushNotificationsEnabled(this.currentUser)) {
|
||||||
|
disableDesktopNotifications();
|
||||||
|
registerPushNotifications(
|
||||||
|
this.currentUser,
|
||||||
|
this.router,
|
||||||
|
this.appEvents
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
unsubscribePushNotifications(this.currentUser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
teardown() {
|
||||||
|
if (!this.currentUser) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.messageBus.unsubscribe(
|
||||||
|
this.reviewableCountsChannel,
|
||||||
|
this.onReviewableCounts
|
||||||
|
);
|
||||||
|
|
||||||
|
this.messageBus.unsubscribe(
|
||||||
|
`/notification/${this.currentUser.id}`,
|
||||||
|
this.onNotification
|
||||||
|
);
|
||||||
|
|
||||||
|
this.messageBus.unsubscribe(
|
||||||
|
`/user-drafts/${this.currentUser.id}`,
|
||||||
|
this.onUserDrafts
|
||||||
|
);
|
||||||
|
|
||||||
|
this.messageBus.unsubscribe(
|
||||||
|
`/do-not-disturb/${this.currentUser.id}`,
|
||||||
|
this.onDoNotDisturb
|
||||||
|
);
|
||||||
|
|
||||||
|
this.messageBus.unsubscribe(`/user-status`, this.onUserStatus);
|
||||||
|
|
||||||
|
this.messageBus.unsubscribe("/categories", this.onCategories);
|
||||||
|
|
||||||
|
this.messageBus.unsubscribe("/client_settings", this.onClientSettings);
|
||||||
|
|
||||||
|
this.messageBus.unsubscribe(alertChannel(this.currentUser), this.onAlert);
|
||||||
|
},
|
||||||
|
|
||||||
|
@bind
|
||||||
|
onReviewableCounts(data) {
|
||||||
if (data.reviewable_count >= 0) {
|
if (data.reviewable_count >= 0) {
|
||||||
user.updateReviewableCount(data.reviewable_count);
|
this.currentUser.updateReviewableCount(data.reviewable_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user.redesigned_user_menu_enabled) {
|
if (this.currentUser.redesigned_user_menu_enabled) {
|
||||||
user.set("unseen_reviewable_count", data.unseen_reviewable_count);
|
this.currentUser.set(
|
||||||
|
"unseen_reviewable_count",
|
||||||
|
data.unseen_reviewable_count
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
|
||||||
bus.subscribe(
|
@bind
|
||||||
`/notification/${user.id}`,
|
onNotification(data) {
|
||||||
(data) => {
|
const oldUnread = this.currentUser.unread_notifications;
|
||||||
const store = container.lookup("service:store");
|
const oldHighPriority = this.currentUser.unread_high_priority_notifications;
|
||||||
const oldUnread = user.unread_notifications;
|
const oldAllUnread = this.currentUser.all_unread_notifications_count;
|
||||||
const oldHighPriority = user.unread_high_priority_notifications;
|
|
||||||
const oldAllUnread = user.all_unread_notifications_count;
|
|
||||||
|
|
||||||
user.setProperties({
|
this.currentUser.setProperties({
|
||||||
unread_notifications: data.unread_notifications,
|
unread_notifications: data.unread_notifications,
|
||||||
unread_high_priority_notifications:
|
unread_high_priority_notifications:
|
||||||
data.unread_high_priority_notifications,
|
data.unread_high_priority_notifications,
|
||||||
@ -62,19 +152,19 @@ export default {
|
|||||||
oldHighPriority !== data.unread_high_priority_notifications ||
|
oldHighPriority !== data.unread_high_priority_notifications ||
|
||||||
oldAllUnread !== data.all_unread_notifications_count
|
oldAllUnread !== data.all_unread_notifications_count
|
||||||
) {
|
) {
|
||||||
appEvents.trigger("notifications:changed");
|
this.appEvents.trigger("notifications:changed");
|
||||||
|
|
||||||
if (
|
if (
|
||||||
site.mobileView &&
|
this.site.mobileView &&
|
||||||
(data.unread_notifications - oldUnread > 0 ||
|
(data.unread_notifications - oldUnread > 0 ||
|
||||||
data.unread_high_priority_notifications - oldHighPriority > 0 ||
|
data.unread_high_priority_notifications - oldHighPriority > 0 ||
|
||||||
data.all_unread_notifications_count - oldAllUnread > 0)
|
data.all_unread_notifications_count - oldAllUnread > 0)
|
||||||
) {
|
) {
|
||||||
appEvents.trigger("header:update-topic", null, 5000);
|
this.appEvents.trigger("header:update-topic", null, 5000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const stale = store.findStale(
|
const stale = this.store.findStale(
|
||||||
"notification",
|
"notification",
|
||||||
{},
|
{},
|
||||||
{ cacheKey: "recent-notifications" }
|
{ cacheKey: "recent-notifications" }
|
||||||
@ -121,66 +211,55 @@ export default {
|
|||||||
stale.results.set("content", newNotifications);
|
stale.results.set("content", newNotifications);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
user.notification_channel_position
|
|
||||||
);
|
|
||||||
|
|
||||||
bus.subscribe(`/user-drafts/${user.id}`, (data) => {
|
@bind
|
||||||
user.updateDraftProperties(data);
|
onUserDrafts(data) {
|
||||||
});
|
this.currentUser.updateDraftProperties(data);
|
||||||
|
},
|
||||||
|
|
||||||
bus.subscribe(`/do-not-disturb/${user.get("id")}`, (data) => {
|
@bind
|
||||||
user.updateDoNotDisturbStatus(data.ends_at);
|
onDoNotDisturb(data) {
|
||||||
});
|
this.currentUser.updateDoNotDisturbStatus(data.ends_at);
|
||||||
|
},
|
||||||
|
|
||||||
bus.subscribe(`/user-status`, (data) => {
|
@bind
|
||||||
appEvents.trigger("user-status:changed", data);
|
onUserStatus(data) {
|
||||||
});
|
this.appEvents.trigger("user-status:changed", data);
|
||||||
|
},
|
||||||
|
|
||||||
const site = container.lookup("service:site");
|
@bind
|
||||||
const router = container.lookup("router:main");
|
onCategories(data) {
|
||||||
|
|
||||||
bus.subscribe("/categories", (data) => {
|
|
||||||
(data.categories || []).forEach((c) => {
|
(data.categories || []).forEach((c) => {
|
||||||
const mutedCategoryIds = user.muted_category_ids?.concat(
|
const mutedCategoryIds = this.currentUser.muted_category_ids?.concat(
|
||||||
user.indirectly_muted_category_ids
|
this.currentUser.indirectly_muted_category_ids
|
||||||
);
|
);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
mutedCategoryIds &&
|
mutedCategoryIds &&
|
||||||
mutedCategoryIds.includes(c.parent_category_id) &&
|
mutedCategoryIds.includes(c.parent_category_id) &&
|
||||||
!mutedCategoryIds.includes(c.id)
|
!mutedCategoryIds.includes(c.id)
|
||||||
) {
|
) {
|
||||||
user.set(
|
this.currentUser.set(
|
||||||
"indirectly_muted_category_ids",
|
"indirectly_muted_category_ids",
|
||||||
user.indirectly_muted_category_ids.concat(c.id)
|
this.currentUser.indirectly_muted_category_ids.concat(c.id)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return site.updateCategory(c);
|
|
||||||
|
return this.site.updateCategory(c);
|
||||||
});
|
});
|
||||||
|
|
||||||
(data.deleted_categories || []).forEach((id) =>
|
(data.deleted_categories || []).forEach((id) =>
|
||||||
site.removeCategory(id)
|
this.site.removeCategory(id)
|
||||||
);
|
);
|
||||||
});
|
},
|
||||||
|
|
||||||
bus.subscribe(
|
@bind
|
||||||
"/client_settings",
|
onClientSettings(data) {
|
||||||
(data) => (siteSettings[data.name] = data.value)
|
this.siteSettings[data.name] = data.value;
|
||||||
);
|
},
|
||||||
|
|
||||||
if (!isTesting()) {
|
@bind
|
||||||
bus.subscribe(alertChannel(user), (data) =>
|
onAlert(data) {
|
||||||
onNotification(data, siteSettings, user)
|
return onNotification(data, this.siteSettings, this.currentUser);
|
||||||
);
|
|
||||||
|
|
||||||
initDesktopNotifications(bus, appEvents);
|
|
||||||
|
|
||||||
if (isPushNotificationsEnabled(user)) {
|
|
||||||
disableDesktopNotifications();
|
|
||||||
registerPushNotifications(user, router, appEvents);
|
|
||||||
} else {
|
|
||||||
unsubscribePushNotifications(user);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,29 +1,41 @@
|
|||||||
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "user-tips",
|
name: "user-tips",
|
||||||
after: "message-bus",
|
after: "message-bus",
|
||||||
|
|
||||||
initialize(container) {
|
initialize(container) {
|
||||||
const currentUser = container.lookup("service:current-user");
|
this.currentUser = container.lookup("service:current-user");
|
||||||
if (!currentUser) {
|
if (!this.currentUser) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const messageBus = container.lookup("service:message-bus");
|
this.messageBus = container.lookup("service:message-bus");
|
||||||
const site = container.lookup("service:site");
|
this.site = container.lookup("service:site");
|
||||||
|
|
||||||
messageBus.subscribe("/user-tips", function (seenUserTips) {
|
this.messageBus.subscribe("/user-tips", this.onMessage);
|
||||||
currentUser.set("seen_popups", seenUserTips);
|
},
|
||||||
if (!currentUser.user_option) {
|
|
||||||
currentUser.set("user_option", {});
|
teardown() {
|
||||||
|
this.messageBus?.unsubscribe("/user-tips", this.onMessage);
|
||||||
|
},
|
||||||
|
|
||||||
|
@bind
|
||||||
|
onMessage(seenUserTips) {
|
||||||
|
this.currentUser.set("seen_popups", seenUserTips);
|
||||||
|
|
||||||
|
if (!this.currentUser.user_option) {
|
||||||
|
this.currentUser.set("user_option", {});
|
||||||
}
|
}
|
||||||
currentUser.set("user_option.seen_popups", seenUserTips);
|
|
||||||
|
this.currentUser.set("user_option.seen_popups", seenUserTips);
|
||||||
|
|
||||||
(seenUserTips || []).forEach((userTipId) => {
|
(seenUserTips || []).forEach((userTipId) => {
|
||||||
currentUser.hideUserTipForever(
|
this.currentUser.hideUserTipForever(
|
||||||
Object.keys(site.user_tips).find(
|
Object.keys(this.site.user_tips).find(
|
||||||
(id) => site.user_tips[id] === userTipId
|
(id) => this.site.user_tips[id] === userTipId
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,15 +1,24 @@
|
|||||||
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "welcome-topic-banner",
|
name: "welcome-topic-banner",
|
||||||
after: "message-bus",
|
after: "message-bus",
|
||||||
|
|
||||||
initialize(container) {
|
initialize(container) {
|
||||||
const site = container.lookup("service:site");
|
this.site = container.lookup("service:site");
|
||||||
|
this.messageBus = container.lookup("service:message-bus");
|
||||||
|
|
||||||
if (site.show_welcome_topic_banner) {
|
if (this.site.show_welcome_topic_banner) {
|
||||||
const messageBus = container.lookup("service:message-bus");
|
this.messageBus.subscribe("/site/welcome-topic-banner", this.onMessage);
|
||||||
messageBus.subscribe("/site/welcome-topic-banner", (disabled) => {
|
|
||||||
site.set("show_welcome_topic_banner", disabled);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
teardown() {
|
||||||
|
this.messageBus.unsubscribe("/site/welcome-topic-banner", this.onMessage);
|
||||||
|
},
|
||||||
|
|
||||||
|
@bind
|
||||||
|
onMessage(disabled) {
|
||||||
|
this.site.set("show_welcome_topic_banner", disabled);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import EmberObject, { get } from "@ember/object";
|
import EmberObject, { get } from "@ember/object";
|
||||||
import discourseComputed, { bind, on } from "discourse-common/utils/decorators";
|
import discourseComputed, { bind } from "discourse-common/utils/decorators";
|
||||||
import Category from "discourse/models/category";
|
import Category from "discourse/models/category";
|
||||||
import { deepEqual, deepMerge } from "discourse-common/lib/object";
|
import { deepEqual, deepMerge } from "discourse-common/lib/object";
|
||||||
import DiscourseURL from "discourse/lib/url";
|
import DiscourseURL from "discourse/lib/url";
|
||||||
@ -46,13 +46,33 @@ function hasMutedTags(topicTags, mutedTags, siteSettings) {
|
|||||||
const TopicTrackingState = EmberObject.extend({
|
const TopicTrackingState = EmberObject.extend({
|
||||||
messageCount: 0,
|
messageCount: 0,
|
||||||
|
|
||||||
@on("init")
|
init() {
|
||||||
_setup() {
|
this._super(...arguments);
|
||||||
|
|
||||||
this.states = new Map();
|
this.states = new Map();
|
||||||
this.stateChangeCallbacks = {};
|
this.stateChangeCallbacks = {};
|
||||||
this._trackedTopicLimit = 4000;
|
this._trackedTopicLimit = 4000;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
willDestroy() {
|
||||||
|
this._super(...arguments);
|
||||||
|
|
||||||
|
this.messageBus.unsubscribe("/latest", this._processChannelPayload);
|
||||||
|
|
||||||
|
if (this.currentUser) {
|
||||||
|
this.messageBus.unsubscribe("/new", this._processChannelPayload);
|
||||||
|
this.messageBus.unsubscribe(`/unread`, this._processChannelPayload);
|
||||||
|
this.messageBus.unsubscribe(
|
||||||
|
`/unread/${this.currentUser.id}`,
|
||||||
|
this._processChannelPayload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.messageBus.unsubscribe("/delete", this.onDeleteMessage);
|
||||||
|
this.messageBus.unsubscribe("/recover", this.onRecoverMessage);
|
||||||
|
this.messageBus.unsubscribe("/destroy", this.onDestroyMessage);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subscribe to MessageBus channels which are used for publishing changes
|
* Subscribe to MessageBus channels which are used for publishing changes
|
||||||
* to the tracking state. Each message received will modify state for
|
* to the tracking state. Each message received will modify state for
|
||||||
@ -74,26 +94,34 @@ const TopicTrackingState = EmberObject.extend({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.messageBus.subscribe("/delete", (msg) => {
|
this.messageBus.subscribe("/delete", this.onDeleteMessage);
|
||||||
|
this.messageBus.subscribe("/recover", this.onRecoverMessage);
|
||||||
|
this.messageBus.subscribe("/destroy", this.onDestroyMessage);
|
||||||
|
},
|
||||||
|
|
||||||
|
@bind
|
||||||
|
onDeleteMessage(msg) {
|
||||||
this.modifyStateProp(msg, "deleted", true);
|
this.modifyStateProp(msg, "deleted", true);
|
||||||
this.incrementMessageCount();
|
this.incrementMessageCount();
|
||||||
});
|
},
|
||||||
|
|
||||||
this.messageBus.subscribe("/recover", (msg) => {
|
@bind
|
||||||
|
onRecoverMessage(msg) {
|
||||||
this.modifyStateProp(msg, "deleted", false);
|
this.modifyStateProp(msg, "deleted", false);
|
||||||
this.incrementMessageCount();
|
this.incrementMessageCount();
|
||||||
});
|
},
|
||||||
|
|
||||||
this.messageBus.subscribe("/destroy", (msg) => {
|
@bind
|
||||||
|
onDestroyMessage(msg) {
|
||||||
this.incrementMessageCount();
|
this.incrementMessageCount();
|
||||||
const currentRoute = DiscourseURL.router.currentRoute.parent;
|
const currentRoute = DiscourseURL.router.currentRoute.parent;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
currentRoute.name === "topic" &&
|
currentRoute.name === "topic" &&
|
||||||
parseInt(currentRoute.params.id, 10) === msg.topic_id
|
parseInt(currentRoute.params.id, 10) === msg.topic_id
|
||||||
) {
|
) {
|
||||||
DiscourseURL.redirectTo("/");
|
DiscourseURL.redirectTo("/");
|
||||||
}
|
}
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
mutedTopics() {
|
mutedTopics() {
|
||||||
@ -280,7 +308,7 @@ const TopicTrackingState = EmberObject.extend({
|
|||||||
* @param {String} filter - Valid values are all, categories, and any topic list
|
* @param {String} filter - Valid values are all, categories, and any topic list
|
||||||
* filters e.g. latest, unread, new. As well as this
|
* filters e.g. latest, unread, new. As well as this
|
||||||
* specific category and tag URLs like tag/test/l/latest,
|
* specific category and tag URLs like tag/test/l/latest,
|
||||||
* c/cat/subcat/6/l/latest or tags/c/cat/subcat/6/test/l/latest.
|
* c/cat/sub-cat/6/l/latest or tags/c/cat/sub-cat/6/test/l/latest.
|
||||||
*/
|
*/
|
||||||
trackIncoming(filter) {
|
trackIncoming(filter) {
|
||||||
this.newIncoming = [];
|
this.newIncoming = [];
|
||||||
@ -555,7 +583,7 @@ const TopicTrackingState = EmberObject.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Using the array of tags provided, tallys up all topics via forEachTracked
|
* Using the array of tags provided, tallies up all topics via forEachTracked
|
||||||
* that we are tracking, separated into new/unread/total.
|
* that we are tracking, separated into new/unread/total.
|
||||||
*
|
*
|
||||||
* Total is only counted if opts.includeTotal is specified.
|
* Total is only counted if opts.includeTotal is specified.
|
||||||
|
@ -40,13 +40,13 @@ export default {
|
|||||||
// to register a null value for anon
|
// to register a null value for anon
|
||||||
app.register("service:current-user", currentUser, { instantiate: false });
|
app.register("service:current-user", currentUser, { instantiate: false });
|
||||||
|
|
||||||
const topicTrackingState = TopicTrackingState.create({
|
this.topicTrackingState = TopicTrackingState.create({
|
||||||
messageBus: container.lookup("service:message-bus"),
|
messageBus: container.lookup("service:message-bus"),
|
||||||
siteSettings,
|
siteSettings,
|
||||||
currentUser,
|
currentUser,
|
||||||
});
|
});
|
||||||
|
|
||||||
app.register("service:topic-tracking-state", topicTrackingState, {
|
app.register("service:topic-tracking-state", this.topicTrackingState, {
|
||||||
instantiate: false,
|
instantiate: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -108,6 +108,11 @@ export default {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
startTracking(topicTrackingState);
|
startTracking(this.topicTrackingState);
|
||||||
|
},
|
||||||
|
|
||||||
|
teardown() {
|
||||||
|
// Manually call `willDestroy` as this isn't an actual `Service`
|
||||||
|
this.topicTrackingState.willDestroy();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import DiscourseRoute from "discourse/routes/discourse";
|
import DiscourseRoute from "discourse/routes/discourse";
|
||||||
import { isPresent } from "@ember/utils";
|
import { isPresent } from "@ember/utils";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default DiscourseRoute.extend({
|
export default DiscourseRoute.extend({
|
||||||
model(params) {
|
model(params) {
|
||||||
@ -51,7 +52,23 @@ export default DiscourseRoute.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
activate() {
|
activate() {
|
||||||
this._updateClaimedBy = (data) => {
|
this.messageBus.subscribe("/reviewable_claimed", this._updateClaimedBy);
|
||||||
|
this.messageBus.subscribe(
|
||||||
|
this._reviewableCountsChannel,
|
||||||
|
this._updateReviewables
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
deactivate() {
|
||||||
|
this.messageBus.unsubscribe("/reviewable_claimed", this._updateClaimedBy);
|
||||||
|
this.messageBus.unsubscribe(
|
||||||
|
this._reviewableCountsChannel,
|
||||||
|
this._updateReviewables
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
@bind
|
||||||
|
_updateClaimedBy(data) {
|
||||||
const reviewables = this.controller.reviewables;
|
const reviewables = this.controller.reviewables;
|
||||||
if (reviewables) {
|
if (reviewables) {
|
||||||
const user = data.user
|
const user = data.user
|
||||||
@ -63,9 +80,10 @@ export default DiscourseRoute.extend({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
|
||||||
this._updateReviewables = (data) => {
|
@bind
|
||||||
|
_updateReviewables(data) {
|
||||||
if (data.updates) {
|
if (data.updates) {
|
||||||
this.controller.reviewables.forEach((reviewable) => {
|
this.controller.reviewables.forEach((reviewable) => {
|
||||||
const updates = data.updates[reviewable.id];
|
const updates = data.updates[reviewable.id];
|
||||||
@ -74,31 +92,16 @@ export default DiscourseRoute.extend({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
this.messageBus.subscribe("/reviewable_claimed", this._updateClaimedBy);
|
|
||||||
this.messageBus.subscribe(
|
|
||||||
this._reviewableCountsChannel(),
|
|
||||||
this._updateReviewables
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
deactivate() {
|
get _reviewableCountsChannel() {
|
||||||
this.messageBus.unsubscribe("/reviewable_claimed", this._updateClaimedBy);
|
return this.currentUser.redesigned_user_menu_enabled
|
||||||
this.messageBus.unsubscribe(
|
? `/reviewable_counts/${this.currentUser.id}`
|
||||||
this._reviewableCountsChannel(),
|
: "/reviewable_counts";
|
||||||
this._updateReviewables
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
@action
|
@action
|
||||||
refreshRoute() {
|
refreshRoute() {
|
||||||
this.refresh();
|
this.refresh();
|
||||||
},
|
},
|
||||||
|
|
||||||
_reviewableCountsChannel() {
|
|
||||||
return this.currentUser.redesigned_user_menu_enabled
|
|
||||||
? `/reviewable_counts/${this.currentUser.id}`
|
|
||||||
: "/reviewable_counts";
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
@ -2,25 +2,9 @@ import DiscourseRoute from "discourse/routes/discourse";
|
|||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import User from "discourse/models/user";
|
import User from "discourse/models/user";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default DiscourseRoute.extend({
|
export default DiscourseRoute.extend({
|
||||||
titleToken() {
|
|
||||||
const username = this.modelFor("user").username;
|
|
||||||
if (username) {
|
|
||||||
return [I18n.t("user.profile"), username];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
@action
|
|
||||||
undoRevokeApiKey(key) {
|
|
||||||
key.undoRevoke();
|
|
||||||
},
|
|
||||||
|
|
||||||
@action
|
|
||||||
revokeApiKey(key) {
|
|
||||||
key.revoke();
|
|
||||||
},
|
|
||||||
|
|
||||||
beforeModel() {
|
beforeModel() {
|
||||||
if (this.siteSettings.hide_user_profiles_from_public && !this.currentUser) {
|
if (this.siteSettings.hide_user_profiles_from_public && !this.currentUser) {
|
||||||
this.replaceWith("discovery");
|
this.replaceWith("discovery");
|
||||||
@ -68,29 +52,64 @@ export default DiscourseRoute.extend({
|
|||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
|
||||||
const user = this.modelFor("user");
|
const user = this.modelFor("user");
|
||||||
this.messageBus.subscribe(`/u/${user.username_lower}`, (data) =>
|
this.messageBus.subscribe(`/u/${user.username_lower}`, this.onUserMessage);
|
||||||
user.loadUserAction(data)
|
this.messageBus.subscribe(
|
||||||
|
`/u/${user.username_lower}/counters`,
|
||||||
|
this.onUserCountersMessage
|
||||||
);
|
);
|
||||||
this.messageBus.subscribe(`/u/${user.username_lower}/counters`, (data) => {
|
|
||||||
user.setProperties(data);
|
|
||||||
Object.entries(data).forEach(([key, value]) =>
|
|
||||||
this.appEvents.trigger(
|
|
||||||
`count-updated:${user.username_lower}:${key}`,
|
|
||||||
value
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
deactivate() {
|
deactivate() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
|
||||||
const user = this.modelFor("user");
|
const user = this.modelFor("user");
|
||||||
this.messageBus.unsubscribe(`/u/${user.username_lower}`);
|
this.messageBus.unsubscribe(
|
||||||
this.messageBus.unsubscribe(`/u/${user.username_lower}/counters`);
|
`/u/${user.username_lower}`,
|
||||||
|
this.onUserMessage
|
||||||
|
);
|
||||||
|
this.messageBus.unsubscribe(
|
||||||
|
`/u/${user.username_lower}/counters`,
|
||||||
|
this.onUserCountersMessage
|
||||||
|
);
|
||||||
user.stopTrackingStatus();
|
user.stopTrackingStatus();
|
||||||
|
|
||||||
// Remove the search context
|
// Remove the search context
|
||||||
this.searchService.set("searchContext", null);
|
this.searchService.set("searchContext", null);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@bind
|
||||||
|
onUserMessage(data) {
|
||||||
|
const user = this.modelFor("user");
|
||||||
|
return user.loadUserAction(data);
|
||||||
|
},
|
||||||
|
|
||||||
|
@bind
|
||||||
|
onUserCountersMessage(data) {
|
||||||
|
const user = this.modelFor("user");
|
||||||
|
user.setProperties(data);
|
||||||
|
|
||||||
|
Object.entries(data).forEach(([key, value]) =>
|
||||||
|
this.appEvents.trigger(
|
||||||
|
`count-updated:${user.username_lower}:${key}`,
|
||||||
|
value
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
titleToken() {
|
||||||
|
const username = this.modelFor("user").username;
|
||||||
|
if (username) {
|
||||||
|
return [I18n.t("user.profile"), username];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
@action
|
||||||
|
undoRevokeApiKey(key) {
|
||||||
|
key.undoRevoke();
|
||||||
|
},
|
||||||
|
|
||||||
|
@action
|
||||||
|
revokeApiKey(key) {
|
||||||
|
key.revoke();
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
import discourseComputed, {
|
||||||
|
bind,
|
||||||
|
observes,
|
||||||
|
} from "discourse-common/utils/decorators";
|
||||||
import Service from "@ember/service";
|
import Service from "@ember/service";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import { autoUpdatingRelativeAge } from "discourse/lib/formatter";
|
import { autoUpdatingRelativeAge } from "discourse/lib/formatter";
|
||||||
@ -29,9 +32,21 @@ export default Service.extend({
|
|||||||
this.set("text", text);
|
this.set("text", text);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.messageBus.subscribe("/logs_error_rate_exceeded", (data) => {
|
this.messageBus.subscribe("/logs_error_rate_exceeded", this.onLogRateLimit);
|
||||||
const duration = data.duration;
|
},
|
||||||
const rate = data.rate;
|
|
||||||
|
willDestroy() {
|
||||||
|
this._super(...arguments);
|
||||||
|
|
||||||
|
this.messageBus.unsubscribe(
|
||||||
|
"/logs_error_rate_exceeded",
|
||||||
|
this.onLogRateLimit
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
@bind
|
||||||
|
onLogRateLimit(data) {
|
||||||
|
const { duration, rate } = data;
|
||||||
let siteSettingLimit = 0;
|
let siteSettingLimit = 0;
|
||||||
|
|
||||||
if (duration === "minute") {
|
if (duration === "minute") {
|
||||||
@ -46,15 +61,12 @@ export default Service.extend({
|
|||||||
this.set(
|
this.set(
|
||||||
"text",
|
"text",
|
||||||
I18n.messageFormat(`logs_error_rate_notice.${translationKey}`, {
|
I18n.messageFormat(`logs_error_rate_notice.${translationKey}`, {
|
||||||
relativeAge: autoUpdatingRelativeAge(
|
relativeAge: autoUpdatingRelativeAge(new Date(data.publish_at * 1000)),
|
||||||
new Date(data.publish_at * 1000)
|
|
||||||
),
|
|
||||||
rate,
|
rate,
|
||||||
limit: siteSettingLimit,
|
limit: siteSettingLimit,
|
||||||
url: getURL("/logs"),
|
url: getURL("/logs"),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
@discourseComputed("text")
|
@discourseComputed("text")
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { Promise } from "rsvp";
|
import { Promise } from "rsvp";
|
||||||
|
|
||||||
import Service from "@ember/service";
|
import Service from "@ember/service";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import { bind, on } from "discourse-common/utils/decorators";
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
import { deepEqual, deepMerge } from "discourse-common/lib/object";
|
import { deepEqual, deepMerge } from "discourse-common/lib/object";
|
||||||
import {
|
import {
|
||||||
@ -21,8 +20,9 @@ const PrivateMessageTopicTrackingState = Service.extend({
|
|||||||
filter: null,
|
filter: null,
|
||||||
activeGroup: null,
|
activeGroup: null,
|
||||||
|
|
||||||
@on("init")
|
init() {
|
||||||
_setup() {
|
this._super(...arguments);
|
||||||
|
|
||||||
this.states = new Map();
|
this.states = new Map();
|
||||||
this.statesModificationCounter = 0;
|
this.statesModificationCounter = 0;
|
||||||
this.isTracking = false;
|
this.isTracking = false;
|
||||||
@ -30,6 +30,16 @@ const PrivateMessageTopicTrackingState = Service.extend({
|
|||||||
this.stateChangeCallbacks = new Map();
|
this.stateChangeCallbacks = new Map();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
willDestroy() {
|
||||||
|
this._super(...arguments);
|
||||||
|
|
||||||
|
if (this.currentUser) {
|
||||||
|
this.messageBus.unsubscribe(this.userChannel(), this._processMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.messageBus.unsubscribe(this.groupChannel("*"), this._processMessage);
|
||||||
|
},
|
||||||
|
|
||||||
onStateChange(key, callback) {
|
onStateChange(key, callback) {
|
||||||
this.stateChangeCallbacks.set(key, callback);
|
this.stateChangeCallbacks.set(key, callback);
|
||||||
},
|
},
|
||||||
@ -43,14 +53,6 @@ const PrivateMessageTopicTrackingState = Service.extend({
|
|||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
this._establishChannels();
|
|
||||||
|
|
||||||
return this._loadInitialState().finally(() => {
|
|
||||||
this.set("isTracking", true);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
_establishChannels() {
|
|
||||||
this.messageBus.subscribe(this.userChannel(), this._processMessage);
|
this.messageBus.subscribe(this.userChannel(), this._processMessage);
|
||||||
|
|
||||||
this.currentUser.groupsWithMessages?.forEach((group) => {
|
this.currentUser.groupsWithMessages?.forEach((group) => {
|
||||||
@ -59,6 +61,10 @@ const PrivateMessageTopicTrackingState = Service.extend({
|
|||||||
this._processMessage
|
this._processMessage
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return this._loadInitialState().finally(() => {
|
||||||
|
this.set("isTracking", true);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
lookupCount(type, opts = {}) {
|
lookupCount(type, opts = {}) {
|
||||||
|
@ -5,7 +5,7 @@ import { popupAjaxError } from "discourse/lib/ajax-error";
|
|||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import getURL from "discourse-common/lib/get-url";
|
import getURL from "discourse-common/lib/get-url";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed, { bind } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
channel: null,
|
channel: null,
|
||||||
@ -56,7 +56,21 @@ export default Component.extend({
|
|||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
if (this.currentUser.admin) {
|
if (this.currentUser.admin) {
|
||||||
this.messageBus.subscribe("/chat/channel-archive-status", (busData) => {
|
this.messageBus.subscribe("/chat/channel-archive-status", this.onMessage);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
willDestroyElement() {
|
||||||
|
this._super(...arguments);
|
||||||
|
this.messageBus.unsubscribe("/chat/channel-archive-status", this.onMessage);
|
||||||
|
},
|
||||||
|
|
||||||
|
_getTopicUrl() {
|
||||||
|
return getURL(`/t/-/${this.channel.archive_topic_id}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
@bind
|
||||||
|
onMessage(busData) {
|
||||||
if (busData.chat_channel_id === this.channel.id) {
|
if (busData.chat_channel_id === this.channel.id) {
|
||||||
this.channel.setProperties({
|
this.channel.setProperties({
|
||||||
archive_failed: busData.archive_failed,
|
archive_failed: busData.archive_failed,
|
||||||
@ -66,16 +80,5 @@ export default Component.extend({
|
|||||||
total_messages: busData.total_messages,
|
total_messages: busData.total_messages,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
willDestroyElement() {
|
|
||||||
this._super(...arguments);
|
|
||||||
this.messageBus.unsubscribe("/chat/channel-archive-status");
|
|
||||||
},
|
|
||||||
|
|
||||||
_getTopicUrl() {
|
|
||||||
return getURL(`/t/-/${this.channel.archive_topic_id}`);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -1496,23 +1496,26 @@ export default Component.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_unsubscribeToUpdates(channelId) {
|
_unsubscribeToUpdates(channelId) {
|
||||||
this.messageBus.unsubscribe(`/chat/${channelId}`);
|
this.messageBus.unsubscribe(`/chat/${channelId}`, this.onMessage);
|
||||||
},
|
},
|
||||||
|
|
||||||
_subscribeToUpdates(channelId) {
|
_subscribeToUpdates(channelId) {
|
||||||
this._unsubscribeToUpdates(channelId);
|
this._unsubscribeToUpdates(channelId);
|
||||||
this.messageBus.subscribe(
|
this.messageBus.subscribe(
|
||||||
`/chat/${channelId}`,
|
`/chat/${channelId}`,
|
||||||
(busData) => {
|
this.onMessage,
|
||||||
|
this.details.channel_message_bus_last_id
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
@bind
|
||||||
|
onMessage(busData) {
|
||||||
if (!this.details.can_load_more_future || busData.type !== "sent") {
|
if (!this.details.can_load_more_future || busData.type !== "sent") {
|
||||||
this.handleMessage(busData);
|
this.handleMessage(busData);
|
||||||
} else {
|
} else {
|
||||||
this.set("hasNewMessages", true);
|
this.set("hasNewMessages", true);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
this.details.channel_message_bus_last_id
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
@bind
|
@bind
|
||||||
_forceBodyScroll() {
|
_forceBodyScroll() {
|
||||||
|
@ -102,13 +102,11 @@ export default class ChatNotificationManager extends Service {
|
|||||||
this.set("_countChatInDocTitle", true);
|
this.set("_countChatInDocTitle", true);
|
||||||
|
|
||||||
if (!this._subscribedToChat) {
|
if (!this._subscribedToChat) {
|
||||||
this.messageBus.subscribe(this._chatAlertChannel(), (data) =>
|
this.messageBus.subscribe(this._chatAlertChannel(), this.onMessage);
|
||||||
onNotification(data, this.siteSettings, this.currentUser)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts.only && this._subscribedToCore) {
|
if (opts.only && this._subscribedToCore) {
|
||||||
this.messageBus.unsubscribe(this._coreAlertChannel());
|
this.messageBus.unsubscribe(this._coreAlertChannel(), this.onMessage);
|
||||||
this.set("_subscribedToCore", false);
|
this.set("_subscribedToCore", false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,17 +116,20 @@ export default class ChatNotificationManager extends Service {
|
|||||||
this.set("_countChatInDocTitle", false);
|
this.set("_countChatInDocTitle", false);
|
||||||
}
|
}
|
||||||
if (!this._subscribedToCore) {
|
if (!this._subscribedToCore) {
|
||||||
this.messageBus.subscribe(this._coreAlertChannel(), (data) =>
|
this.messageBus.subscribe(this._coreAlertChannel(), this.onMessage);
|
||||||
onNotification(data, this.siteSettings, this.currentUser)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.only && this._subscribedToChat) {
|
if (this.only && this._subscribedToChat) {
|
||||||
this.messageBus.unsubscribe(this._chatAlertChannel());
|
this.messageBus.unsubscribe(this._chatAlertChannel(), this.onMessage);
|
||||||
this.set("_subscribedToChat", false);
|
this.set("_subscribedToChat", false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bind
|
||||||
|
onMessage(data) {
|
||||||
|
return onNotification(data, this.siteSettings, this.currentUser);
|
||||||
|
}
|
||||||
|
|
||||||
_shouldRun() {
|
_shouldRun() {
|
||||||
return this.chat.userCanChat && !isTesting();
|
return this.chat.userCanChat && !isTesting();
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import EmberObject, { computed } from "@ember/object";
|
|||||||
import ChatApi from "discourse/plugins/chat/discourse/lib/chat-api";
|
import ChatApi from "discourse/plugins/chat/discourse/lib/chat-api";
|
||||||
import discourseLater from "discourse-common/lib/later";
|
import discourseLater from "discourse-common/lib/later";
|
||||||
import userPresent from "discourse/lib/user-presence";
|
import userPresent from "discourse/lib/user-presence";
|
||||||
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export const LIST_VIEW = "list_view";
|
export const LIST_VIEW = "list_view";
|
||||||
export const CHAT_VIEW = "chat_view";
|
export const CHAT_VIEW = "chat_view";
|
||||||
@ -57,6 +58,8 @@ export default class Chat extends Service {
|
|||||||
isNetworkUnreliable = false;
|
isNetworkUnreliable = false;
|
||||||
@and("currentUser.has_chat_enabled", "siteSettings.chat_enabled") userCanChat;
|
@and("currentUser.has_chat_enabled", "siteSettings.chat_enabled") userCanChat;
|
||||||
_fetchingChannels = null;
|
_fetchingChannels = null;
|
||||||
|
_onNewMentionsCallbacks = new Map();
|
||||||
|
_onNewMessagesCallbacks = new Map();
|
||||||
|
|
||||||
@computed("currentUser.staff", "currentUser.groups.[]")
|
@computed("currentUser.staff", "currentUser.groups.[]")
|
||||||
get userCanDirectMessage() {
|
get userCanDirectMessage() {
|
||||||
@ -607,7 +610,132 @@ export default class Chat extends Service {
|
|||||||
_subscribeToChannelMetadata() {
|
_subscribeToChannelMetadata() {
|
||||||
this.messageBus.subscribe(
|
this.messageBus.subscribe(
|
||||||
"/chat/channel-metadata",
|
"/chat/channel-metadata",
|
||||||
(busData) => {
|
this._onChannelMetadata,
|
||||||
|
this.messageBusLastIds.channel_metadata
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_subscribeToChannelEdits() {
|
||||||
|
this.messageBus.subscribe(
|
||||||
|
"/chat/channel-edits",
|
||||||
|
this._onChannelEdits,
|
||||||
|
this.messageBusLastIds.channel_edits
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_subscribeToChannelStatusChange() {
|
||||||
|
this.messageBus.subscribe("/chat/channel-status", this._onChannelStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
_unsubscribeFromChannelStatusChange() {
|
||||||
|
this.messageBus.unsubscribe("/chat/channel-status", this._onChannelStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
_unsubscribeFromChannelEdits() {
|
||||||
|
this.messageBus.unsubscribe("/chat/channel-edits", this._onChannelEdits);
|
||||||
|
}
|
||||||
|
|
||||||
|
_unsubscribeFromChannelMetadata() {
|
||||||
|
this.messageBus.unsubscribe(
|
||||||
|
"/chat/channel-metadata",
|
||||||
|
this._onChannelMetadata
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_subscribeToNewChannelUpdates() {
|
||||||
|
this.messageBus.subscribe(
|
||||||
|
"/chat/new-channel",
|
||||||
|
this._onNewChannel,
|
||||||
|
this.messageBusLastIds.new_channel
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_unsubscribeFromNewDmChannelUpdates() {
|
||||||
|
this.messageBus.unsubscribe("/chat/new-channel", this._onNewChannel);
|
||||||
|
}
|
||||||
|
|
||||||
|
_subscribeToSingleUpdateChannel(channel) {
|
||||||
|
if (channel.current_user_membership.muted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We do this first so we don't multi-subscribe to mention + messages
|
||||||
|
// messageBus channels for this chat channel, since _subscribeToSingleUpdateChannel
|
||||||
|
// is called from multiple places.
|
||||||
|
this._unsubscribeFromChatChannel(channel);
|
||||||
|
|
||||||
|
if (!channel.isDirectMessageChannel) {
|
||||||
|
this._subscribeToMentionChannel(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._subscribeToNewMessagesChannel(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
_subscribeToMentionChannel(channel) {
|
||||||
|
const onNewMentions = () => {
|
||||||
|
const trackingState =
|
||||||
|
this.currentUser.chat_channel_tracking_state[channel.id];
|
||||||
|
|
||||||
|
if (trackingState) {
|
||||||
|
const count = (trackingState.unread_mentions || 0) + 1;
|
||||||
|
trackingState.set("unread_mentions", count);
|
||||||
|
this.userChatChannelTrackingStateChanged();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this._onNewMentionsCallbacks.set(channel.id, onNewMentions);
|
||||||
|
|
||||||
|
this.messageBus.subscribe(
|
||||||
|
`/chat/${channel.id}/new-mentions`,
|
||||||
|
onNewMentions,
|
||||||
|
channel.message_bus_last_ids.new_mentions
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_subscribeToNewMessagesChannel(channel) {
|
||||||
|
const onNewMessages = (busData) => {
|
||||||
|
const trackingState =
|
||||||
|
this.currentUser.chat_channel_tracking_state[channel.id];
|
||||||
|
|
||||||
|
if (busData.user_id === this.currentUser.id) {
|
||||||
|
// User sent message, update tracking state to no unread
|
||||||
|
trackingState.set("chat_message_id", busData.message_id);
|
||||||
|
} else {
|
||||||
|
// Ignored user sent message, update tracking state to no unread
|
||||||
|
if (this.currentUser.ignored_users.includes(busData.username)) {
|
||||||
|
trackingState.set("chat_message_id", busData.message_id);
|
||||||
|
} else {
|
||||||
|
// Message from other user. Increment trackings state
|
||||||
|
if (busData.message_id > (trackingState.chat_message_id || 0)) {
|
||||||
|
trackingState.set("unread_count", trackingState.unread_count + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.userChatChannelTrackingStateChanged();
|
||||||
|
channel.set("last_message_sent_at", new Date());
|
||||||
|
|
||||||
|
const directMessageChannel = (this.directMessageChannels || []).findBy(
|
||||||
|
"id",
|
||||||
|
parseInt(channel.id, 10)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (directMessageChannel) {
|
||||||
|
this.reSortDirectMessageChannels();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this._onNewMessagesCallbacks.set(channel.id, onNewMessages);
|
||||||
|
|
||||||
|
this.messageBus.subscribe(
|
||||||
|
`/chat/${channel.id}/new-messages`,
|
||||||
|
onNewMessages,
|
||||||
|
channel.message_bus_last_ids.new_messages
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@bind
|
||||||
|
_onChannelMetadata(busData) {
|
||||||
this.getChannelBy("id", busData.chat_channel_id).then((channel) => {
|
this.getChannelBy("id", busData.chat_channel_id).then((channel) => {
|
||||||
if (channel) {
|
if (channel) {
|
||||||
channel.setProperties({
|
channel.setProperties({
|
||||||
@ -616,15 +744,10 @@ export default class Chat extends Service {
|
|||||||
this.appEvents.trigger("chat:refresh-channel-members");
|
this.appEvents.trigger("chat:refresh-channel-members");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
|
||||||
this.messageBusLastIds.channel_metadata
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_subscribeToChannelEdits() {
|
@bind
|
||||||
this.messageBus.subscribe(
|
_onChannelEdits(busData) {
|
||||||
"/chat/channel-edits",
|
|
||||||
(busData) => {
|
|
||||||
this.getChannelBy("id", busData.chat_channel_id).then((channel) => {
|
this.getChannelBy("id", busData.chat_channel_id).then((channel) => {
|
||||||
if (channel) {
|
if (channel) {
|
||||||
channel.setProperties({
|
channel.setProperties({
|
||||||
@ -633,13 +756,10 @@ export default class Chat extends Service {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
|
||||||
this.messageBusLastIds.channel_edits
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_subscribeToChannelStatusChange() {
|
@bind
|
||||||
this.messageBus.subscribe("/chat/channel-status", (busData) => {
|
_onChannelStatus(busData) {
|
||||||
this.getChannelBy("id", busData.chat_channel_id).then((channel) => {
|
this.getChannelBy("id", busData.chat_channel_id).then((channel) => {
|
||||||
if (!channel) {
|
if (!channel) {
|
||||||
return;
|
return;
|
||||||
@ -662,104 +782,11 @@ export default class Chat extends Service {
|
|||||||
|
|
||||||
this.appEvents.trigger("chat:refresh-channel", channel.id);
|
this.appEvents.trigger("chat:refresh-channel", channel.id);
|
||||||
}, this.messageBusLastIds.channel_status);
|
}, this.messageBusLastIds.channel_status);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_unsubscribeFromChannelStatusChange() {
|
@bind
|
||||||
this.messageBus.unsubscribe("/chat/channel-status");
|
_onNewChannel(busData) {
|
||||||
}
|
|
||||||
|
|
||||||
_unsubscribeFromChannelEdits() {
|
|
||||||
this.messageBus.unsubscribe("/chat/channel-edits");
|
|
||||||
}
|
|
||||||
|
|
||||||
_unsubscribeFromChannelMetadata() {
|
|
||||||
this.messageBus.unsubscribe("/chat/channel-metadata");
|
|
||||||
}
|
|
||||||
|
|
||||||
_subscribeToNewChannelUpdates() {
|
|
||||||
this.messageBus.subscribe(
|
|
||||||
"/chat/new-channel",
|
|
||||||
(busData) => {
|
|
||||||
this.startTrackingChannel(ChatChannel.create(busData.chat_channel));
|
this.startTrackingChannel(ChatChannel.create(busData.chat_channel));
|
||||||
},
|
|
||||||
this.messageBusLastIds.new_channel
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_unsubscribeFromNewDmChannelUpdates() {
|
|
||||||
this.messageBus.unsubscribe("/chat/new-channel");
|
|
||||||
}
|
|
||||||
|
|
||||||
_subscribeToSingleUpdateChannel(channel) {
|
|
||||||
if (channel.current_user_membership.muted) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We do this first so we don't multi-subscribe to mention + messages
|
|
||||||
// messageBus channels for this chat channel, since _subscribeToSingleUpdateChannel
|
|
||||||
// is called from multiple places.
|
|
||||||
this._unsubscribeFromChatChannel(channel);
|
|
||||||
|
|
||||||
if (!channel.isDirectMessageChannel) {
|
|
||||||
this._subscribeToMentionChannel(channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._subscribeToNewMessagesChannel(channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
_subscribeToMentionChannel(channel) {
|
|
||||||
this.messageBus.subscribe(
|
|
||||||
`/chat/${channel.id}/new-mentions`,
|
|
||||||
() => {
|
|
||||||
const trackingState =
|
|
||||||
this.currentUser.chat_channel_tracking_state[channel.id];
|
|
||||||
if (trackingState) {
|
|
||||||
trackingState.set(
|
|
||||||
"unread_mentions",
|
|
||||||
(trackingState.unread_mentions || 0) + 1
|
|
||||||
);
|
|
||||||
this.userChatChannelTrackingStateChanged();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
channel.message_bus_last_ids.new_mentions
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_subscribeToNewMessagesChannel(channel) {
|
|
||||||
this.messageBus.subscribe(
|
|
||||||
`/chat/${channel.id}/new-messages`,
|
|
||||||
(busData) => {
|
|
||||||
const trackingState =
|
|
||||||
this.currentUser.chat_channel_tracking_state[channel.id];
|
|
||||||
|
|
||||||
if (busData.user_id === this.currentUser.id) {
|
|
||||||
// User sent message, update tracking state to no unread
|
|
||||||
trackingState.set("chat_message_id", busData.message_id);
|
|
||||||
} else {
|
|
||||||
// Ignored user sent message, update tracking state to no unread
|
|
||||||
if (this.currentUser.ignored_users.includes(busData.username)) {
|
|
||||||
trackingState.set("chat_message_id", busData.message_id);
|
|
||||||
} else {
|
|
||||||
// Message from other user. Increment trackings state
|
|
||||||
if (busData.message_id > (trackingState.chat_message_id || 0)) {
|
|
||||||
trackingState.set("unread_count", trackingState.unread_count + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.userChatChannelTrackingStateChanged();
|
|
||||||
channel.set("last_message_sent_at", new Date());
|
|
||||||
|
|
||||||
const directMessageChannel = (this.directMessageChannels || []).findBy(
|
|
||||||
"id",
|
|
||||||
parseInt(channel.id, 10)
|
|
||||||
);
|
|
||||||
if (directMessageChannel) {
|
|
||||||
this.reSortDirectMessageChannels();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
channel.message_bus_last_ids.new_messages
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async followChannel(channel) {
|
async followChannel(channel) {
|
||||||
@ -787,16 +814,29 @@ export default class Chat extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_unsubscribeFromChatChannel(channel) {
|
_unsubscribeFromChatChannel(channel) {
|
||||||
this.messageBus.unsubscribe(`/chat/${channel.id}/new-messages`);
|
this.messageBus.unsubscribe("/chat/*", this._onNewMessagesCallbacks);
|
||||||
if (!channel.isDirectMessageChannel) {
|
if (!channel.isDirectMessageChannel) {
|
||||||
this.messageBus.unsubscribe(`/chat/${channel.id}/new-mentions`);
|
this.messageBus.unsubscribe("/chat/*", this._onNewMentionsCallbacks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_subscribeToUserTrackingChannel() {
|
_subscribeToUserTrackingChannel() {
|
||||||
this.messageBus.subscribe(
|
this.messageBus.subscribe(
|
||||||
`/chat/user-tracking-state/${this.currentUser.id}`,
|
`/chat/user-tracking-state/${this.currentUser.id}`,
|
||||||
(busData, _, messageId) => {
|
this._onUserTrackingState,
|
||||||
|
this.messageBusLastIds.user_tracking_state
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_unsubscribeFromUserTrackingChannel() {
|
||||||
|
this.messageBus.unsubscribe(
|
||||||
|
`/chat/user-tracking-state/${this.currentUser.id}`,
|
||||||
|
this._onUserTrackingState
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@bind
|
||||||
|
_onUserTrackingState(busData, _, messageId) {
|
||||||
const lastId = this.lastUserTrackingMessageId;
|
const lastId = this.lastUserTrackingMessageId;
|
||||||
|
|
||||||
// we don't want this state to go backwards, only catch
|
// we don't want this state to go backwards, only catch
|
||||||
@ -813,21 +853,13 @@ export default class Chat extends Service {
|
|||||||
|
|
||||||
const trackingState =
|
const trackingState =
|
||||||
this.currentUser.chat_channel_tracking_state[busData.chat_channel_id];
|
this.currentUser.chat_channel_tracking_state[busData.chat_channel_id];
|
||||||
|
|
||||||
if (trackingState) {
|
if (trackingState) {
|
||||||
trackingState.set("chat_message_id", busData.chat_message_id);
|
trackingState.set("chat_message_id", busData.chat_message_id);
|
||||||
trackingState.set("unread_count", 0);
|
trackingState.set("unread_count", 0);
|
||||||
trackingState.set("unread_mentions", 0);
|
trackingState.set("unread_mentions", 0);
|
||||||
this.userChatChannelTrackingStateChanged();
|
this.userChatChannelTrackingStateChanged();
|
||||||
}
|
}
|
||||||
},
|
|
||||||
this.messageBusLastIds.user_tracking_state
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_unsubscribeFromUserTrackingChannel() {
|
|
||||||
this.messageBus.unsubscribe(
|
|
||||||
`/chat/user-tracking-state/${this.currentUser.id}`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resetTrackingStateForChannel(channelId) {
|
resetTrackingStateForChannel(channelId) {
|
||||||
|
@ -1,43 +1,61 @@
|
|||||||
import { withPluginApi } from "discourse/lib/plugin-api";
|
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||||
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
const PLUGIN_ID = "new-user-narrative";
|
|
||||||
|
|
||||||
function initialize(api) {
|
|
||||||
const messageBus = api.container.lookup("service:message-bus");
|
|
||||||
const currentUser = api.getCurrentUser();
|
|
||||||
const appEvents = api.container.lookup("service:app-events");
|
|
||||||
|
|
||||||
api.modifyClass("component:site-header", {
|
|
||||||
pluginId: PLUGIN_ID,
|
|
||||||
didInsertElement() {
|
|
||||||
this._super(...arguments);
|
|
||||||
this.dispatch("header:search-context-trigger", "header");
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
api.attachWidgetAction("header", "headerSearchContextTrigger", function () {
|
|
||||||
if (this.site.mobileView) {
|
|
||||||
this.state.skipSearchContext = false;
|
|
||||||
} else {
|
|
||||||
this.state.contextEnabled = true;
|
|
||||||
this.state.searchContextType = "topic";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (messageBus && currentUser) {
|
|
||||||
messageBus.subscribe(`/new_user_narrative/tutorial_search`, () => {
|
|
||||||
appEvents.trigger("header:search-context-trigger");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "new-user-narrative",
|
name: "new-user-narrative",
|
||||||
|
|
||||||
initialize(container) {
|
initialize(container) {
|
||||||
const siteSettings = container.lookup("service:site-settings");
|
const siteSettings = container.lookup("service:site-settings");
|
||||||
if (siteSettings.discourse_narrative_bot_enabled) {
|
|
||||||
withPluginApi("0.8.7", initialize);
|
if (!siteSettings.discourse_narrative_bot_enabled) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.messageBus = container.lookup("service:message-bus");
|
||||||
|
this.appEvents = container.lookup("service:app-events");
|
||||||
|
|
||||||
|
withPluginApi("0.8.7", (api) => {
|
||||||
|
const currentUser = api.getCurrentUser();
|
||||||
|
|
||||||
|
if (!currentUser) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
api.dispatchWidgetAppEvent(
|
||||||
|
"site-header",
|
||||||
|
"header",
|
||||||
|
"header:search-context-trigger"
|
||||||
|
);
|
||||||
|
|
||||||
|
api.attachWidgetAction(
|
||||||
|
"header",
|
||||||
|
"headerSearchContextTrigger",
|
||||||
|
function () {
|
||||||
|
if (this.site.mobileView) {
|
||||||
|
this.state.skipSearchContext = false;
|
||||||
|
} else {
|
||||||
|
this.state.contextEnabled = true;
|
||||||
|
this.state.searchContextType = "topic";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
this.messageBus.subscribe(
|
||||||
|
"/new_user_narrative/tutorial_search",
|
||||||
|
this.onMessage
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
teardown() {
|
||||||
|
this.messageBus?.unsubscribe(
|
||||||
|
"/new_user_narrative/tutorial_search",
|
||||||
|
this.onMessage
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
@bind
|
||||||
|
onMessage() {
|
||||||
|
this.appEvents.trigger("header:search-context-trigger");
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import EmberObject from "@ember/object";
|
import EmberObject from "@ember/object";
|
||||||
import WidgetGlue from "discourse/widgets/glue";
|
import WidgetGlue from "discourse/widgets/glue";
|
||||||
import { getRegister } from "discourse-common/lib/get-owner";
|
import { getRegister } from "discourse-common/lib/get-owner";
|
||||||
import { observes } from "discourse-common/utils/decorators";
|
import { bind, observes } from "discourse-common/utils/decorators";
|
||||||
import { withPluginApi } from "discourse/lib/plugin-api";
|
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||||
|
|
||||||
const PLUGIN_ID = "discourse-poll";
|
const PLUGIN_ID = "discourse-poll";
|
||||||
@ -34,16 +34,19 @@ function initializePolls(api) {
|
|||||||
|
|
||||||
subscribe() {
|
subscribe() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
this.messageBus.subscribe(`/polls/${this.model.id}`, (msg) => {
|
this.messageBus.subscribe(`/polls/${this.model.id}`, this._onPollMessage);
|
||||||
const post = this.get("model.postStream").findLoadedPost(msg.post_id);
|
|
||||||
post?.set("polls", msg.polls);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
unsubscribe() {
|
unsubscribe() {
|
||||||
this.messageBus.unsubscribe("/polls/*");
|
this.messageBus.unsubscribe("/polls/*", this._onPollMessage);
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@bind
|
||||||
|
_onPollMessage(msg) {
|
||||||
|
const post = this.get("model.postStream").findLoadedPost(msg.post_id);
|
||||||
|
post?.set("polls", msg.polls);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
api.modifyClass("model:post", {
|
api.modifyClass("model:post", {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user