mirror of
https://github.com/discourse/discourse.git
synced 2026-08-19 01:14:56 -05:00
DEV: Rough chat message loading and posting in thread (#20579)
This commit does a couple of things: * Adds the ability to load messages in the chat thread panel when it is open. This just loads the most recent N messages, same as a channel, and does nothing more, no scrolling or anything like that. * Displays the messages in an extremely simple unordered list with no additional features. * Allows posting new messages to the thread, and echoes them into the main channel, but does not respond to any sort of MessageBus events. I've moved messages/clearMessages/addMessages/findMessage code out of the `ChatChannel` model and into a new `ChatMessagesManager` class, which is instantiated in both the `ChatChannel` model and the `ChatThread` model. This allows both to manage messages in the same way via the `TrackedArray` pattern. This is all hidden behind experimental flags, there is no way to make this not completely broken in a single commit. Much more work and refactoring needs to be done first. Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
This commit is contained in:
co-authored by
Joffrey JAFFEUX
parent
1859025228
commit
0a06974a8a
@@ -107,6 +107,7 @@ module Chat
|
|||||||
content: content,
|
content: content,
|
||||||
staged_id: params[:staged_id],
|
staged_id: params[:staged_id],
|
||||||
upload_ids: params[:upload_ids],
|
upload_ids: params[:upload_ids],
|
||||||
|
thread_id: params[:thread_id],
|
||||||
)
|
)
|
||||||
|
|
||||||
return render_json_error(chat_message_creator.error) if chat_message_creator.failed?
|
return render_json_error(chat_message_creator.error) if chat_message_creator.failed?
|
||||||
@@ -215,6 +216,7 @@ module Chat
|
|||||||
|
|
||||||
messages = preloaded_chat_message_query.where(chat_channel: @chat_channel)
|
messages = preloaded_chat_message_query.where(chat_channel: @chat_channel)
|
||||||
messages = messages.with_deleted if guardian.can_moderate_chat?(@chatable)
|
messages = messages.with_deleted if guardian.can_moderate_chat?(@chatable)
|
||||||
|
messages = messages.where(thread_id: params[:thread_id]) if params[:thread_id]
|
||||||
|
|
||||||
if message_id.present?
|
if message_id.present?
|
||||||
condition = direction == PAST ? "<" : ">"
|
condition = direction == PAST ? "<" : ">"
|
||||||
@@ -305,6 +307,7 @@ module Chat
|
|||||||
|
|
||||||
messages = preloaded_chat_message_query.where(chat_channel: @chat_channel)
|
messages = preloaded_chat_message_query.where(chat_channel: @chat_channel)
|
||||||
messages = messages.with_deleted if guardian.can_moderate_chat?(@chatable)
|
messages = messages.with_deleted if guardian.can_moderate_chat?(@chatable)
|
||||||
|
messages = messages.where(thread_id: params[:thread_id]) if params[:thread_id]
|
||||||
|
|
||||||
past_messages =
|
past_messages =
|
||||||
messages
|
messages
|
||||||
|
|||||||
@@ -75,7 +75,7 @@
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{#if (and this.loadedOnce (not @channel.canLoadMorePast))}}
|
{{#if (and this.loadedOnce (not @channel.messagesManager.canLoadMorePast))}}
|
||||||
<div class="all-loaded-message">
|
<div class="all-loaded-message">
|
||||||
{{i18n "chat.all_loaded"}}
|
{{i18n "chat.all_loaded"}}
|
||||||
</div>
|
</div>
|
||||||
@@ -85,7 +85,7 @@
|
|||||||
<ChatScrollToBottomArrow
|
<ChatScrollToBottomArrow
|
||||||
@scrollToBottom={{this.scrollToLatestMessage}}
|
@scrollToBottom={{this.scrollToLatestMessage}}
|
||||||
@hasNewMessages={{this.hasNewMessages}}
|
@hasNewMessages={{this.hasNewMessages}}
|
||||||
@show={{or this.needsArrow @channel.canLoadMoreFuture}}
|
@show={{or this.needsArrow @channel.messagesManager.canLoadMoreFuture}}
|
||||||
@channel={{@channel}}
|
@channel={{@channel}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ export default class ChatLivePane extends Component {
|
|||||||
|
|
||||||
// Technically we could keep messages to avoid re-fetching them, but
|
// Technically we could keep messages to avoid re-fetching them, but
|
||||||
// it's not worth the complexity for now
|
// it's not worth the complexity for now
|
||||||
this.args.channel?.clearMessages();
|
this.args.channel?.messagesManager?.clearMessages();
|
||||||
|
|
||||||
if (this._loadedChannelId !== this.args.channel?.id) {
|
if (this._loadedChannelId !== this.args.channel?.id) {
|
||||||
this._unsubscribeToUpdates(this._loadedChannelId);
|
this._unsubscribeToUpdates(this._loadedChannelId);
|
||||||
@@ -221,8 +221,8 @@ export default class ChatLivePane extends Component {
|
|||||||
const loadingMoreKey = `loadingMore${capitalize(direction)}`;
|
const loadingMoreKey = `loadingMore${capitalize(direction)}`;
|
||||||
|
|
||||||
const canLoadMore = loadingPast
|
const canLoadMore = loadingPast
|
||||||
? this.args.channel.canLoadMorePast
|
? this.args.channel.messagesManager.canLoadMorePast
|
||||||
: this.args.channel.canLoadMoreFuture;
|
: this.args.channel.messagesManager.canLoadMoreFuture;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!canLoadMore ||
|
!canLoadMore ||
|
||||||
@@ -272,7 +272,7 @@ export default class ChatLivePane extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.args.channel.details = meta;
|
this.args.channel.details = meta;
|
||||||
this.args.channel.addMessages(messages);
|
this.args.channel.messagesManager.addMessages(messages);
|
||||||
|
|
||||||
// Edge case for IOS to avoid blank screens
|
// Edge case for IOS to avoid blank screens
|
||||||
// and/or scrolling to bottom losing track of scroll position
|
// and/or scrolling to bottom losing track of scroll position
|
||||||
@@ -301,7 +301,7 @@ export default class ChatLivePane extends Component {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.args.channel?.canLoadMorePast) {
|
if (!this.args.channel?.messagesManager?.canLoadMorePast) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,7 +358,7 @@ export default class ChatLivePane extends Component {
|
|||||||
|
|
||||||
@debounce(100)
|
@debounce(100)
|
||||||
highlightOrFetchMessage(messageId) {
|
highlightOrFetchMessage(messageId) {
|
||||||
const message = this.args.channel.findMessage(messageId);
|
const message = this.#messagesManager?.findMessage(messageId);
|
||||||
if (message) {
|
if (message) {
|
||||||
this.scrollToMessage(message.id, {
|
this.scrollToMessage(message.id, {
|
||||||
highlight: true,
|
highlight: true,
|
||||||
@@ -379,7 +379,7 @@ export default class ChatLivePane extends Component {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const message = this.args.channel.findMessage(messageId);
|
const message = this.#messagesManager?.findMessage(messageId);
|
||||||
if (message?.deletedAt && opts.autoExpand) {
|
if (message?.deletedAt && opts.autoExpand) {
|
||||||
message.expanded = true;
|
message.expanded = true;
|
||||||
}
|
}
|
||||||
@@ -486,7 +486,7 @@ export default class ChatLivePane extends Component {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.args.channel.canLoadMoreFuture) {
|
if (this.#messagesManager?.canLoadMoreFuture) {
|
||||||
this._fetchAndScrollToLatest();
|
this._fetchAndScrollToLatest();
|
||||||
} else if (this.args.channel.messages?.length > 0) {
|
} else if (this.args.channel.messages?.length > 0) {
|
||||||
this.scrollToMessage(
|
this.scrollToMessage(
|
||||||
@@ -525,9 +525,9 @@ export default class ChatLivePane extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
removeMessage(msgData) {
|
removeMessage(msgData) {
|
||||||
const message = this.args.channel.findMessage(msgData.id);
|
const message = this.args.channel.messagesManager.findMessage(msgData.id);
|
||||||
if (message) {
|
if (message) {
|
||||||
this.args.channel.removeMessage(message);
|
this.args.channel.messagesManager.removeMessage(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -579,7 +579,7 @@ export default class ChatLivePane extends Component {
|
|||||||
stagedMessage.channelId = data.chat_message.chat_channel_id;
|
stagedMessage.channelId = data.chat_message.chat_channel_id;
|
||||||
stagedMessage.createdAt = data.chat_message.created_at;
|
stagedMessage.createdAt = data.chat_message.created_at;
|
||||||
|
|
||||||
const inReplyToMsg = this.args.channel.findMessage(
|
const inReplyToMsg = this.args.channel.messagesManager.findMessage(
|
||||||
data.chat_message.in_reply_to?.id
|
data.chat_message.in_reply_to?.id
|
||||||
);
|
);
|
||||||
if (inReplyToMsg && !inReplyToMsg.threadId) {
|
if (inReplyToMsg && !inReplyToMsg.threadId) {
|
||||||
@@ -599,31 +599,36 @@ export default class ChatLivePane extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (data.chat_message.user.id === this.currentUser.id && data.staged_id) {
|
if (data.chat_message.user.id === this.currentUser.id && data.staged_id) {
|
||||||
const stagedMessage = this.args.channel.findStagedMessage(data.staged_id);
|
const stagedMessage = this.args.channel.messagesManager.findStagedMessage(
|
||||||
|
data.staged_id
|
||||||
|
);
|
||||||
if (stagedMessage) {
|
if (stagedMessage) {
|
||||||
return this._handleStagedMessage(stagedMessage, data);
|
return this._handleStagedMessage(stagedMessage, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.args.channel.canLoadMoreFuture) {
|
if (this.args.channel.messagesManager.canLoadMoreFuture) {
|
||||||
// If we can load more messages, we just notice the user of new messages
|
// If we can load more messages, we just notice the user of new messages
|
||||||
this.hasNewMessages = true;
|
this.hasNewMessages = true;
|
||||||
} else if (this.#isTowardsBottom()) {
|
} else if (this.#isTowardsBottom()) {
|
||||||
// If we are at the bottom, we append the message and scroll to it
|
// If we are at the bottom, we append the message and scroll to it
|
||||||
const message = ChatMessage.create(this.args.channel, data.chat_message);
|
const message = ChatMessage.create(this.args.channel, data.chat_message);
|
||||||
this.args.channel.addMessages([message]);
|
|
||||||
|
this.args.channel.messagesManager.addMessages([message]);
|
||||||
this.scrollToLatestMessage();
|
this.scrollToLatestMessage();
|
||||||
this.updateLastReadMessage();
|
this.updateLastReadMessage();
|
||||||
} else {
|
} else {
|
||||||
// If we are almost at the bottom, we append the message and notice the user
|
// If we are almost at the bottom, we append the message and notice the user
|
||||||
const message = ChatMessage.create(this.args.channel, data.chat_message);
|
const message = ChatMessage.create(this.args.channel, data.chat_message);
|
||||||
this.args.channel.addMessages([message]);
|
this.args.channel.messagesManager.addMessages([message]);
|
||||||
this.hasNewMessages = true;
|
this.hasNewMessages = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleProcessedMessage(data) {
|
handleProcessedMessage(data) {
|
||||||
const message = this.args.channel.findMessage(data.chat_message.id);
|
const message = this.args.channel.messagesManager.findMessage(
|
||||||
|
data.chat_message.id
|
||||||
|
);
|
||||||
if (message) {
|
if (message) {
|
||||||
message.cooked = data.chat_message.cooked;
|
message.cooked = data.chat_message.cooked;
|
||||||
this.scrollToLatestMessage();
|
this.scrollToLatestMessage();
|
||||||
@@ -631,14 +636,18 @@ export default class ChatLivePane extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleRefreshMessage(data) {
|
handleRefreshMessage(data) {
|
||||||
const message = this.args.channel.findMessage(data.chat_message.id);
|
const message = this.args.channel.messagesManager.findMessage(
|
||||||
|
data.chat_message.id
|
||||||
|
);
|
||||||
if (message) {
|
if (message) {
|
||||||
message.incrementVersion();
|
message.incrementVersion();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleEditMessage(data) {
|
handleEditMessage(data) {
|
||||||
const message = this.args.channel.findMessage(data.chat_message.id);
|
const message = this.args.channel.messagesManager.findMessage(
|
||||||
|
data.chat_message.id
|
||||||
|
);
|
||||||
if (message) {
|
if (message) {
|
||||||
message.message = data.chat_message.message;
|
message.message = data.chat_message.message;
|
||||||
message.cooked = data.chat_message.cooked;
|
message.cooked = data.chat_message.cooked;
|
||||||
@@ -660,7 +669,7 @@ export default class ChatLivePane extends Component {
|
|||||||
|
|
||||||
handleDeleteMessage(data) {
|
handleDeleteMessage(data) {
|
||||||
const deletedId = data.deleted_id;
|
const deletedId = data.deleted_id;
|
||||||
const targetMsg = this.args.channel.findMessage(deletedId);
|
const targetMsg = this.args.channel.messagesManager.findMessage(deletedId);
|
||||||
|
|
||||||
if (!targetMsg) {
|
if (!targetMsg) {
|
||||||
return;
|
return;
|
||||||
@@ -670,13 +679,15 @@ export default class ChatLivePane extends Component {
|
|||||||
targetMsg.deletedAt = data.deleted_at;
|
targetMsg.deletedAt = data.deleted_at;
|
||||||
targetMsg.expanded = false;
|
targetMsg.expanded = false;
|
||||||
} else {
|
} else {
|
||||||
this.args.channel.removeMessage(targetMsg);
|
this.args.channel.messagesManager.removeMessage(targetMsg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleReactionMessage(data) {
|
handleReactionMessage(data) {
|
||||||
if (data.user.id !== this.currentUser.id) {
|
if (data.user.id !== this.currentUser.id) {
|
||||||
const message = this.args.channel.findMessage(data.chat_message_id);
|
const message = this.args.channel.messagesManager.findMessage(
|
||||||
|
data.chat_message_id
|
||||||
|
);
|
||||||
if (message) {
|
if (message) {
|
||||||
message.react(data.emoji, data.action, data.user, this.currentUser.id);
|
message.react(data.emoji, data.action, data.user, this.currentUser.id);
|
||||||
}
|
}
|
||||||
@@ -684,32 +695,40 @@ export default class ChatLivePane extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleRestoreMessage(data) {
|
handleRestoreMessage(data) {
|
||||||
const message = this.args.channel.findMessage(data.chat_message.id);
|
const message = this.args.channel.messagesManager.findMessage(
|
||||||
|
data.chat_message.id
|
||||||
|
);
|
||||||
if (message) {
|
if (message) {
|
||||||
message.deletedAt = null;
|
message.deletedAt = null;
|
||||||
} else {
|
} else {
|
||||||
this.args.channel.addMessages([
|
this.args.channel.messagesManager.addMessages([
|
||||||
ChatMessage.create(this.args.channel, data.chat_message),
|
ChatMessage.create(this.args.channel, data.chat_message),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMentionWarning(data) {
|
handleMentionWarning(data) {
|
||||||
const message = this.args.channel.findMessage(data.chat_message_id);
|
const message = this.args.channel.messagesManager.findMessage(
|
||||||
|
data.chat_message_id
|
||||||
|
);
|
||||||
if (message) {
|
if (message) {
|
||||||
message.mentionWarning = EmberObject.create(data);
|
message.mentionWarning = EmberObject.create(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSelfFlaggedMessage(data) {
|
handleSelfFlaggedMessage(data) {
|
||||||
const message = this.args.channel.findMessage(data.chat_message_id);
|
const message = this.args.channel.messagesManager.findMessage(
|
||||||
|
data.chat_message_id
|
||||||
|
);
|
||||||
if (message) {
|
if (message) {
|
||||||
message.userFlagStatus = data.user_flag_status;
|
message.userFlagStatus = data.user_flag_status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleFlaggedMessage(data) {
|
handleFlaggedMessage(data) {
|
||||||
const message = this.args.channel.findMessage(data.chat_message_id);
|
const message = this.args.channel.messagesManager.findMessage(
|
||||||
|
data.chat_message_id
|
||||||
|
);
|
||||||
if (message) {
|
if (message) {
|
||||||
message.reviewableId = data.reviewable_id;
|
message.reviewableId = data.reviewable_id;
|
||||||
}
|
}
|
||||||
@@ -719,6 +738,10 @@ export default class ChatLivePane extends Component {
|
|||||||
return this.isDestroying || this.isDestroyed;
|
return this.isDestroying || this.isDestroyed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get #messagesManager() {
|
||||||
|
return this.args.channel?.messagesManager;
|
||||||
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
sendMessage(message, uploads = []) {
|
sendMessage(message, uploads = []) {
|
||||||
resetIdle();
|
resetIdle();
|
||||||
@@ -767,8 +790,8 @@ export default class ChatLivePane extends Component {
|
|||||||
stagedMessage.inReplyTo = this.replyToMsg;
|
stagedMessage.inReplyTo = this.replyToMsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.args.channel.addMessages([stagedMessage]);
|
this.args.channel.messagesManager.addMessages([stagedMessage]);
|
||||||
if (!this.args.channel.canLoadMoreFuture) {
|
if (!this.args.channel.messagesManager.canLoadMoreFuture) {
|
||||||
this.scrollToLatestMessage();
|
this.scrollToLatestMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -817,7 +840,8 @@ export default class ChatLivePane extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_onSendError(id, error) {
|
_onSendError(id, error) {
|
||||||
const stagedMessage = this.args.channel.findStagedMessage(id);
|
const stagedMessage =
|
||||||
|
this.args.channel.messagesManager.findStagedMessage(id);
|
||||||
if (stagedMessage) {
|
if (stagedMessage) {
|
||||||
if (error.jqXHR?.responseJSON?.errors?.length) {
|
if (error.jqXHR?.responseJSON?.errors?.length) {
|
||||||
stagedMessage.error = error.jqXHR.responseJSON.errors[0];
|
stagedMessage.error = error.jqXHR.responseJSON.errors[0];
|
||||||
@@ -916,7 +940,7 @@ export default class ChatLivePane extends Component {
|
|||||||
if (messageId) {
|
if (messageId) {
|
||||||
this.cancelEditing();
|
this.cancelEditing();
|
||||||
|
|
||||||
const message = this.args.channel.findMessage(messageId);
|
const message = this.args.channel.messagesManager.findMessage(messageId);
|
||||||
this.replyToMsg = message;
|
this.replyToMsg = message;
|
||||||
this.appEvents.trigger("chat-composer:reply-to-set", message);
|
this.appEvents.trigger("chat-composer:reply-to-set", message);
|
||||||
this._focusComposer();
|
this._focusComposer();
|
||||||
@@ -928,7 +952,8 @@ export default class ChatLivePane extends Component {
|
|||||||
|
|
||||||
@action
|
@action
|
||||||
replyMessageClicked(message) {
|
replyMessageClicked(message) {
|
||||||
const replyMessageFromLookup = this.args.channel.findMessage(message.id);
|
const replyMessageFromLookup =
|
||||||
|
this.args.channel.messagesManager.findMessage(message.id);
|
||||||
if (replyMessageFromLookup) {
|
if (replyMessageFromLookup) {
|
||||||
this.scrollToMessage(replyMessageFromLookup.id, {
|
this.scrollToMessage(replyMessageFromLookup.id, {
|
||||||
highlight: true,
|
highlight: true,
|
||||||
@@ -944,7 +969,7 @@ export default class ChatLivePane extends Component {
|
|||||||
|
|
||||||
@action
|
@action
|
||||||
editButtonClicked(messageId) {
|
editButtonClicked(messageId) {
|
||||||
const message = this.args.channel.findMessage(messageId);
|
const message = this.args.channel.messagesManager.findMessage(messageId);
|
||||||
this.editingMessage = message;
|
this.editingMessage = message;
|
||||||
this.scrollToLatestMessage();
|
this.scrollToLatestMessage();
|
||||||
this._focusComposer();
|
this._focusComposer();
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
<div class="chat-thread" data-id={{this.thread.id}}>
|
<div
|
||||||
|
class={{concat-class "chat-thread" (if this.loading "loading")}}
|
||||||
|
data-id={{this.thread.id}}
|
||||||
|
{{did-insert this.loadMessages}}
|
||||||
|
>
|
||||||
<div class="chat-thread__header">
|
<div class="chat-thread__header">
|
||||||
<div class="chat-thread__info">
|
<div class="chat-thread__info">
|
||||||
<div class="chat-thread__title">
|
<div class="chat-thread__title">
|
||||||
@@ -14,7 +18,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="chat-thread__om">
|
<p class="chat-thread__om">
|
||||||
{{replace-emoji this.thread.original_message.excerpt}}
|
{{replace-emoji this.thread.originalMessage.excerpt}}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="chat-thread__omu">
|
<div class="chat-thread__omu">
|
||||||
@@ -23,14 +27,36 @@
|
|||||||
}}</span>
|
}}</span>
|
||||||
<ChatMessageAvatar
|
<ChatMessageAvatar
|
||||||
class="chat-thread__omu-avatar"
|
class="chat-thread__omu-avatar"
|
||||||
@message={{this.thread.original_message}}
|
@message={{this.thread.originalMessage}}
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
class="chat-thread__omu-username"
|
class="chat-thread__omu-username"
|
||||||
>{{this.thread.original_message_user.username}}</span>
|
>{{this.thread.originalMessageUser.username}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="chat-thread__messages">
|
<div class="chat-thread__messages">
|
||||||
|
<ul>
|
||||||
|
{{#each this.thread.messages as |message|}}
|
||||||
|
<li><strong>{{message.user.username}}</strong>: {{message.message}}</li>
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
{{#if (or this.loading this.loadingMoreFuture)}}
|
||||||
|
<ChatSkeleton />
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<ChatComposer
|
||||||
|
@canInteractWithChat="true"
|
||||||
|
@sendMessage={{this.sendMessage}}
|
||||||
|
@editMessage={{this.editMessage}}
|
||||||
|
@setReplyTo={{this.setReplyTo}}
|
||||||
|
@loading={{this.sendingLoading}}
|
||||||
|
@editingMessage={{readonly this.editingMessage}}
|
||||||
|
@onCancelEditing={{this.cancelEditing}}
|
||||||
|
@setInReplyToMsg={{this.setInReplyToMsg}}
|
||||||
|
@onEditLastMessageRequested={{this.editLastMessageRequested}}
|
||||||
|
@onValueChange={{this.composerValueChanged}}
|
||||||
|
@chatChannel={{this.channel}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,15 +1,34 @@
|
|||||||
import Component from "@glimmer/component";
|
import Component from "@glimmer/component";
|
||||||
|
import { cloneJSON } from "discourse-common/lib/object";
|
||||||
|
import ChatMessageDraft from "discourse/plugins/chat/discourse/models/chat-message-draft";
|
||||||
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import ChatMessage from "discourse/plugins/chat/discourse/models/chat-message";
|
||||||
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
import { bind, debounce } from "discourse-common/utils/decorators";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import { inject as service } from "@ember/service";
|
import { inject as service } from "@ember/service";
|
||||||
|
|
||||||
|
const PAGE_SIZE = 50;
|
||||||
|
|
||||||
export default class ChatThreadPanel extends Component {
|
export default class ChatThreadPanel extends Component {
|
||||||
@service siteSettings;
|
@service siteSettings;
|
||||||
@service currentUser;
|
@service currentUser;
|
||||||
@service chat;
|
@service chat;
|
||||||
@service router;
|
@service router;
|
||||||
|
@service chatApi;
|
||||||
|
@service chatComposerPresenceManager;
|
||||||
|
@service appEvents;
|
||||||
|
|
||||||
|
@tracked loading;
|
||||||
|
@tracked loadingMorePast;
|
||||||
|
|
||||||
get thread() {
|
get thread() {
|
||||||
return this.chat.activeChannel.activeThread;
|
return this.channel.activeThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
get channel() {
|
||||||
|
return this.chat.activeChannel;
|
||||||
}
|
}
|
||||||
|
|
||||||
get title() {
|
get title() {
|
||||||
@@ -19,4 +38,241 @@ export default class ChatThreadPanel extends Component {
|
|||||||
|
|
||||||
return I18n.t("chat.threads.op_said");
|
return I18n.t("chat.threads.op_said");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
loadMessages() {
|
||||||
|
if (this.args.targetMessageId) {
|
||||||
|
this.requestedTargetMessageId = parseInt(this.args.targetMessageId, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO (martin) Loading/scrolling to selected messagew
|
||||||
|
// this.highlightOrFetchMessage(this.requestedTargetMessageId);
|
||||||
|
// if (this.requestedTargetMessageId) {
|
||||||
|
// } else {
|
||||||
|
this.fetchMessages();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
get _selfDeleted() {
|
||||||
|
return this.isDestroying || this.isDestroyed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@debounce(100)
|
||||||
|
fetchMessages() {
|
||||||
|
if (this._selfDeleted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loadingMorePast = true;
|
||||||
|
this.loading = true;
|
||||||
|
this.thread.messagesManager.clearMessages();
|
||||||
|
|
||||||
|
const findArgs = { pageSize: PAGE_SIZE };
|
||||||
|
|
||||||
|
// TODO (martin) Find arguments for last read etc.
|
||||||
|
// const fetchingFromLastRead = !options.fetchFromLastMessage;
|
||||||
|
// if (this.requestedTargetMessageId) {
|
||||||
|
// findArgs["targetMessageId"] = this.requestedTargetMessageId;
|
||||||
|
// } else if (fetchingFromLastRead) {
|
||||||
|
// findArgs["targetMessageId"] = this._getLastReadId();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
findArgs.threadId = this.thread.id;
|
||||||
|
|
||||||
|
return this.chatApi
|
||||||
|
.messages(this.channel.id, findArgs)
|
||||||
|
.then((results) => {
|
||||||
|
if (this._selfDeleted || this.channel.id !== results.meta.channel_id) {
|
||||||
|
this.router.transitionTo(
|
||||||
|
"chat.channel",
|
||||||
|
"-",
|
||||||
|
results.meta.channel_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const [messages, meta] = this.afterFetchCallback(this.channel, results);
|
||||||
|
this.thread.messagesManager.addMessages(messages);
|
||||||
|
|
||||||
|
// TODO (martin) ECHO MODE
|
||||||
|
this.channel.messagesManager.addMessages(messages);
|
||||||
|
|
||||||
|
// TODO (martin) details needed for thread??
|
||||||
|
this.thread.details = meta;
|
||||||
|
|
||||||
|
// TODO (martin) Scrolling to particular messages
|
||||||
|
// if (this.requestedTargetMessageId) {
|
||||||
|
// this.scrollToMessage(findArgs["targetMessageId"], {
|
||||||
|
// highlight: true,
|
||||||
|
// });
|
||||||
|
// } else if (fetchingFromLastRead) {
|
||||||
|
// this.scrollToMessage(findArgs["targetMessageId"]);
|
||||||
|
// } else if (messages.length) {
|
||||||
|
// this.scrollToMessage(messages.lastObject.id);
|
||||||
|
// }
|
||||||
|
})
|
||||||
|
.catch(this.#handleErrors)
|
||||||
|
.finally(() => {
|
||||||
|
if (this._selfDeleted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.requestedTargetMessageId = null;
|
||||||
|
this.loading = false;
|
||||||
|
this.loadingMorePast = false;
|
||||||
|
|
||||||
|
// this.fillPaneAttempt();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@bind
|
||||||
|
afterFetchCallback(channel, results) {
|
||||||
|
const messages = [];
|
||||||
|
let foundFirstNew = false;
|
||||||
|
|
||||||
|
results.chat_messages.forEach((messageData) => {
|
||||||
|
// If a message has been hidden it is because the current user is ignoring
|
||||||
|
// the user who sent it, so we want to unconditionally hide it, even if
|
||||||
|
// we are going directly to the target
|
||||||
|
if (this.currentUser.ignored_users) {
|
||||||
|
messageData.hidden = this.currentUser.ignored_users.includes(
|
||||||
|
messageData.user.username
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.requestedTargetMessageId === messageData.id) {
|
||||||
|
messageData.expanded = !messageData.hidden;
|
||||||
|
} else {
|
||||||
|
messageData.expanded = !(messageData.hidden || messageData.deleted_at);
|
||||||
|
}
|
||||||
|
|
||||||
|
// newest has to be in after fetcg callback as we don't want to make it
|
||||||
|
// dynamic or it will make the pane jump around, it will disappear on reload
|
||||||
|
if (
|
||||||
|
!foundFirstNew &&
|
||||||
|
messageData.id > channel.currentUserMembership.last_read_message_id
|
||||||
|
) {
|
||||||
|
foundFirstNew = true;
|
||||||
|
messageData.newest = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
messages.push(ChatMessage.create(channel, messageData));
|
||||||
|
});
|
||||||
|
|
||||||
|
return [messages, results.meta];
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
sendMessage(message, uploads = []) {
|
||||||
|
// TODO (martin) For desktop notifications
|
||||||
|
// resetIdle()
|
||||||
|
if (this.sendingLoading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sendingLoading = true;
|
||||||
|
this.channel.draft = ChatMessageDraft.create();
|
||||||
|
|
||||||
|
// TODO (martin) Handling case when channel is not followed???? IDK if we
|
||||||
|
// even let people send messages in threads without this, seems weird.
|
||||||
|
|
||||||
|
const stagedMessage = ChatMessage.createStagedMessage(this.channel, {
|
||||||
|
message,
|
||||||
|
created_at: new Date(),
|
||||||
|
uploads: cloneJSON(uploads),
|
||||||
|
user: this.currentUser,
|
||||||
|
thread_id: this.thread.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.thread.messagesManager.addMessages([stagedMessage]);
|
||||||
|
|
||||||
|
// TODO (martin) Scrolling!!
|
||||||
|
// if (!this.channel.canLoadMoreFuture) {
|
||||||
|
// this.scrollToBottom();
|
||||||
|
// }
|
||||||
|
|
||||||
|
return this.chatApi
|
||||||
|
.sendMessage(this.channel.id, {
|
||||||
|
message: stagedMessage.message,
|
||||||
|
in_reply_to_id: stagedMessage.inReplyTo?.id,
|
||||||
|
staged_id: stagedMessage.stagedId,
|
||||||
|
upload_ids: stagedMessage.uploads.map((upload) => upload.id),
|
||||||
|
thread_id: stagedMessage.threadId,
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
// TODO (martin) Scrolling!!
|
||||||
|
// this.scrollToBottom();
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.#onSendError(stagedMessage.stagedId, error);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
if (this._selfDeleted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.sendingLoading = false;
|
||||||
|
this.#resetAfterSend();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
editMessage() {}
|
||||||
|
// editMessage(chatMessage, newContent, uploads) {}
|
||||||
|
|
||||||
|
@action
|
||||||
|
setReplyTo() {}
|
||||||
|
// setReplyTo(messageId) {}
|
||||||
|
|
||||||
|
@action
|
||||||
|
setInReplyToMsg(inReplyMsg) {
|
||||||
|
this.replyToMsg = inReplyMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
cancelEditing() {
|
||||||
|
this.editingMessage = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
editLastMessageRequested() {}
|
||||||
|
|
||||||
|
@action
|
||||||
|
composerValueChanged() {}
|
||||||
|
// composerValueChanged(value, uploads, replyToMsg) {}
|
||||||
|
|
||||||
|
#handleErrors(error) {
|
||||||
|
switch (error?.jqXHR?.status) {
|
||||||
|
case 429:
|
||||||
|
case 404:
|
||||||
|
popupAjaxError(error);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#onSendError(stagedId, error) {
|
||||||
|
const stagedMessage =
|
||||||
|
this.thread.messagesManager.findStagedMessage(stagedId);
|
||||||
|
if (stagedMessage) {
|
||||||
|
if (error.jqXHR?.responseJSON?.errors?.length) {
|
||||||
|
stagedMessage.error = error.jqXHR.responseJSON.errors[0];
|
||||||
|
} else {
|
||||||
|
this.chat.markNetworkAsUnreliable();
|
||||||
|
stagedMessage.error = "network_error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#resetAfterSend();
|
||||||
|
}
|
||||||
|
|
||||||
|
#resetAfterSend() {
|
||||||
|
if (this._selfDeleted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.replyToMsg = null;
|
||||||
|
this.editingMessage = null;
|
||||||
|
this.chatComposerPresenceManager.notifyState(this.channel.id, false);
|
||||||
|
this.appEvents.trigger("chat-composer:reply-to-set", null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
import { TrackedArray } from "@ember-compat/tracked-built-ins";
|
||||||
|
import { setOwner } from "@ember/application";
|
||||||
|
|
||||||
|
export default class ChatMessagesManager {
|
||||||
|
@tracked messages = new TrackedArray();
|
||||||
|
@tracked canLoadMoreFuture;
|
||||||
|
@tracked canLoadMorePast;
|
||||||
|
|
||||||
|
constructor(owner) {
|
||||||
|
setOwner(this, owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearMessages() {
|
||||||
|
this.messages.clear();
|
||||||
|
|
||||||
|
this.canLoadMoreFuture = null;
|
||||||
|
this.canLoadMorePast = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
addMessages(messages = []) {
|
||||||
|
this.messages = this.messages
|
||||||
|
.concat(messages)
|
||||||
|
.uniqBy("id")
|
||||||
|
.sortBy("createdAt");
|
||||||
|
}
|
||||||
|
|
||||||
|
findMessage(messageId) {
|
||||||
|
return this.messages.find(
|
||||||
|
(message) => message.id === parseInt(messageId, 10)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeMessage(message) {
|
||||||
|
return this.messages.removeObject(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
findStagedMessage(stagedMessageId) {
|
||||||
|
return this.messages.find(
|
||||||
|
(message) => message.staged && message.id === stagedMessageId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -43,7 +43,7 @@ export default class ChatThreadsManager {
|
|||||||
let model = this.#findStale(threadObject.id);
|
let model = this.#findStale(threadObject.id);
|
||||||
|
|
||||||
if (!model) {
|
if (!model) {
|
||||||
model = ChatThread.create(threadObject);
|
model = new ChatThread(threadObject);
|
||||||
this.#cache(model);
|
this.#cache(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,7 +55,6 @@ export default class ChatThreadsManager {
|
|||||||
.thread(channelId, threadId)
|
.thread(channelId, threadId)
|
||||||
.catch(popupAjaxError)
|
.catch(popupAjaxError)
|
||||||
.then((thread) => {
|
.then((thread) => {
|
||||||
this.#cache(thread);
|
|
||||||
return thread;
|
return thread;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import { escapeExpression } from "discourse/lib/utilities";
|
|||||||
import { tracked } from "@glimmer/tracking";
|
import { tracked } from "@glimmer/tracking";
|
||||||
import slugifyChannel from "discourse/plugins/chat/discourse/lib/slugify-channel";
|
import slugifyChannel from "discourse/plugins/chat/discourse/lib/slugify-channel";
|
||||||
import ChatThreadsManager from "discourse/plugins/chat/discourse/lib/chat-threads-manager";
|
import ChatThreadsManager from "discourse/plugins/chat/discourse/lib/chat-threads-manager";
|
||||||
|
import ChatMessagesManager from "discourse/plugins/chat/discourse/lib/chat-messages-manager";
|
||||||
import { getOwner } from "discourse-common/lib/get-owner";
|
import { getOwner } from "discourse-common/lib/get-owner";
|
||||||
import { TrackedArray } from "@ember-compat/tracked-built-ins";
|
|
||||||
|
|
||||||
export const CHATABLE_TYPES = {
|
export const CHATABLE_TYPES = {
|
||||||
directMessageChannel: "DirectMessage",
|
directMessageChannel: "DirectMessage",
|
||||||
@@ -55,18 +55,24 @@ export default class ChatChannel extends RestModel {
|
|||||||
@tracked chatableType;
|
@tracked chatableType;
|
||||||
@tracked status;
|
@tracked status;
|
||||||
@tracked activeThread;
|
@tracked activeThread;
|
||||||
@tracked messages = new TrackedArray();
|
|
||||||
@tracked lastMessageSentAt;
|
@tracked lastMessageSentAt;
|
||||||
@tracked canDeleteOthers;
|
@tracked canDeleteOthers;
|
||||||
@tracked canDeleteSelf;
|
@tracked canDeleteSelf;
|
||||||
@tracked canFlag;
|
@tracked canFlag;
|
||||||
@tracked canLoadMoreFuture;
|
|
||||||
@tracked canLoadMorePast;
|
|
||||||
@tracked canModerate;
|
@tracked canModerate;
|
||||||
@tracked userSilenced;
|
@tracked userSilenced;
|
||||||
@tracked draft;
|
@tracked draft;
|
||||||
|
|
||||||
threadsManager = new ChatThreadsManager(getOwner(this));
|
threadsManager = new ChatThreadsManager(getOwner(this));
|
||||||
|
messagesManager = new ChatMessagesManager(getOwner(this));
|
||||||
|
|
||||||
|
get messages() {
|
||||||
|
return this.messagesManager.messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
set messages(messages) {
|
||||||
|
this.messagesManager.messages = messages;
|
||||||
|
}
|
||||||
|
|
||||||
get escapedTitle() {
|
get escapedTitle() {
|
||||||
return escapeExpression(this.title);
|
return escapeExpression(this.title);
|
||||||
@@ -126,46 +132,16 @@ export default class ChatChannel extends RestModel {
|
|||||||
this.canFlag = details.can_flag ?? false;
|
this.canFlag = details.can_flag ?? false;
|
||||||
this.canModerate = details.can_moderate ?? false;
|
this.canModerate = details.can_moderate ?? false;
|
||||||
if (details.can_load_more_future !== undefined) {
|
if (details.can_load_more_future !== undefined) {
|
||||||
this.canLoadMoreFuture = details.can_load_more_future;
|
this.messagesManager.canLoadMoreFuture = details.can_load_more_future;
|
||||||
}
|
}
|
||||||
if (details.can_load_more_past !== undefined) {
|
if (details.can_load_more_past !== undefined) {
|
||||||
this.canLoadMorePast = details.can_load_more_past;
|
this.messagesManager.canLoadMorePast = details.can_load_more_past;
|
||||||
}
|
}
|
||||||
this.userSilenced = details.user_silenced ?? false;
|
this.userSilenced = details.user_silenced ?? false;
|
||||||
this.status = details.channel_status;
|
this.status = details.channel_status;
|
||||||
this.channelMessageBusLastId = details.channel_message_bus_last_id;
|
this.channelMessageBusLastId = details.channel_message_bus_last_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
clearMessages() {
|
|
||||||
this.messages.clear();
|
|
||||||
|
|
||||||
this.canLoadMoreFuture = null;
|
|
||||||
this.canLoadMorePast = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
addMessages(messages = []) {
|
|
||||||
this.messages = this.messages
|
|
||||||
.concat(messages)
|
|
||||||
.uniqBy("id")
|
|
||||||
.sortBy("createdAt");
|
|
||||||
}
|
|
||||||
|
|
||||||
findMessage(messageId) {
|
|
||||||
return this.messages.find(
|
|
||||||
(message) => message.id === parseInt(messageId, 10)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
removeMessage(message) {
|
|
||||||
return this.messages.removeObject(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
findStagedMessage(stagedMessageId) {
|
|
||||||
return this.messages.find(
|
|
||||||
(message) => message.staged && message.id === stagedMessageId
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
canModifyMessages(user) {
|
canModifyMessages(user) {
|
||||||
if (user.staff) {
|
if (user.staff) {
|
||||||
return !STAFF_READONLY_STATUSES.includes(this.status);
|
return !STAFF_READONLY_STATUSES.includes(this.status);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import RestModel from "discourse/models/rest";
|
import { getOwner } from "discourse-common/lib/get-owner";
|
||||||
|
import ChatMessagesManager from "discourse/plugins/chat/discourse/lib/chat-messages-manager";
|
||||||
import User from "discourse/models/user";
|
import User from "discourse/models/user";
|
||||||
import { escapeExpression } from "discourse/lib/utilities";
|
import { escapeExpression } from "discourse/lib/utilities";
|
||||||
import { tracked } from "@glimmer/tracking";
|
import { tracked } from "@glimmer/tracking";
|
||||||
@@ -10,22 +11,42 @@ export const THREAD_STATUSES = {
|
|||||||
archived: "archived",
|
archived: "archived",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class ChatThread extends RestModel {
|
export default class ChatThread {
|
||||||
@tracked title;
|
@tracked title;
|
||||||
@tracked status;
|
@tracked status;
|
||||||
|
|
||||||
|
messagesManager = new ChatMessagesManager(getOwner(this));
|
||||||
|
|
||||||
|
constructor(args = {}) {
|
||||||
|
this.title = args.title;
|
||||||
|
this.id = args.id;
|
||||||
|
this.status = args.status;
|
||||||
|
|
||||||
|
this.originalMessageUser = this.#initUserModel(args.original_message_user);
|
||||||
|
|
||||||
|
// TODO (martin) Not sure if ChatMessage is needed here, original_message
|
||||||
|
// only has a small subset of message stuff.
|
||||||
|
this.originalMessage = args.original_message;
|
||||||
|
this.originalMessage.user = this.originalMessageUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
get messages() {
|
||||||
|
return this.messagesManager.messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
set messages(messages) {
|
||||||
|
this.messagesManager.messages = messages;
|
||||||
|
}
|
||||||
|
|
||||||
get escapedTitle() {
|
get escapedTitle() {
|
||||||
return escapeExpression(this.title);
|
return escapeExpression(this.title);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ChatThread.reopenClass({
|
#initUserModel(user) {
|
||||||
create(args) {
|
if (!user || user instanceof User) {
|
||||||
args = args || {};
|
return user;
|
||||||
if (!args.original_message_user instanceof User) {
|
|
||||||
args.original_message_user = User.create(args.original_message_user);
|
|
||||||
}
|
}
|
||||||
args.original_message.user = args.original_message_user;
|
|
||||||
return this._super(args);
|
return User.create(user);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@@ -10,8 +10,7 @@ export default class ChatChannelRoute extends DiscourseRoute {
|
|||||||
|
|
||||||
@action
|
@action
|
||||||
willTransition(transition) {
|
willTransition(transition) {
|
||||||
this.chat.activeChannel.activeThread = null;
|
this.#closeThread();
|
||||||
this.chatStateManager.closeSidePanel();
|
|
||||||
|
|
||||||
if (transition?.to?.name === "chat.channel.index") {
|
if (transition?.to?.name === "chat.channel.index") {
|
||||||
const targetChannelId = transition?.to?.parent?.params?.channelId;
|
const targetChannelId = transition?.to?.parent?.params?.channelId;
|
||||||
@@ -19,7 +18,7 @@ export default class ChatChannelRoute extends DiscourseRoute {
|
|||||||
targetChannelId &&
|
targetChannelId &&
|
||||||
parseInt(targetChannelId, 10) !== this.chat.activeChannel.id
|
parseInt(targetChannelId, 10) !== this.chat.activeChannel.id
|
||||||
) {
|
) {
|
||||||
this.chat.activeChannel.clearMessages();
|
this.chat.activeChannel.messagesManager.clearMessages();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,4 +28,10 @@ export default class ChatChannelRoute extends DiscourseRoute {
|
|||||||
this.chat.updatePresence();
|
this.chat.updatePresence();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#closeThread() {
|
||||||
|
this.chat.activeChannel.activeThread?.messagesManager?.clearMessages();
|
||||||
|
this.chat.activeChannel.activeThread = null;
|
||||||
|
this.chatStateManager.closeSidePanel();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -261,6 +261,10 @@ export default class ChatApi extends Service {
|
|||||||
if (data.direction) {
|
if (data.direction) {
|
||||||
args.direction = data.direction;
|
args.direction = data.direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.threadId) {
|
||||||
|
args.thread_id = data.threadId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ajax(path, { data: args });
|
return ajax(path, { data: args });
|
||||||
|
|||||||
Reference in New Issue
Block a user