mirror of
https://github.com/discourse/discourse.git
synced 2026-08-10 04:58:31 -05:00
FIX: improves draft for channels (#21724)
This commit attempts to correctly change draft when the channel changes. It moves responsibility to the composer instead of the channel. A new service `chatDraftsManager` is being introduced here to allow finer control and pave the way for future thread draft support. These changes also now allow an editing message to be stored as a draft.
This commit is contained in:
@@ -43,6 +43,7 @@ export default class ChatLivePane extends Component {
|
||||
@service appEvents;
|
||||
@service messageBus;
|
||||
@service site;
|
||||
@service chatDraftsManager;
|
||||
|
||||
@tracked loading = false;
|
||||
@tracked loadingMorePast = false;
|
||||
@@ -116,11 +117,6 @@ export default class ChatLivePane extends Component {
|
||||
if (this._loadedChannelId !== this.args.channel?.id) {
|
||||
this.unsubscribeToUpdates(this._loadedChannelId);
|
||||
this.chatChannelPane.selectingMessages = false;
|
||||
|
||||
if (this.args.channel.draft) {
|
||||
this.chatChannelComposer.message = this.args.channel.draft;
|
||||
}
|
||||
|
||||
this._loadedChannelId = this.args.channel?.id;
|
||||
}
|
||||
|
||||
@@ -642,6 +638,7 @@ export default class ChatLivePane extends Component {
|
||||
.editMessage(this.args.channel.id, message.id, data)
|
||||
.catch(popupAjaxError)
|
||||
.finally(() => {
|
||||
this.chatDraftsManager.remove({ channelId: this.args.channel.id });
|
||||
this.chatChannelPane.sending = false;
|
||||
});
|
||||
}
|
||||
@@ -704,7 +701,7 @@ export default class ChatLivePane extends Component {
|
||||
return;
|
||||
}
|
||||
|
||||
this.args.channel.draft = null;
|
||||
this.chatDraftsManager.remove({ channelId: this.args.channel.id });
|
||||
this.chatChannelPane.sending = false;
|
||||
});
|
||||
}
|
||||
|
||||
+5
-1
@@ -1,4 +1,8 @@
|
||||
<div class="chat-composer-message-details" data-id={{@message.id}}>
|
||||
<div
|
||||
class="chat-composer-message-details"
|
||||
data-id={{@message.id}}
|
||||
data-action={{if @message.editing "edit" "reply"}}
|
||||
>
|
||||
<div class="chat-reply">
|
||||
{{d-icon (if @message.editing "pencil-alt" "reply")}}
|
||||
<ChatUserAvatar @user={{@message.user}} />
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
{{did-update this.didUpdateMessage this.currentMessage}}
|
||||
{{did-update this.didUpdateInReplyTo this.currentMessage.inReplyTo}}
|
||||
{{did-insert this.setup}}
|
||||
{{did-insert this.didUpdateChannel}}
|
||||
{{did-update this.didUpdateChannel @channel.id}}
|
||||
{{will-destroy this.teardown}}
|
||||
{{will-destroy this.cancelPersistDraft}}
|
||||
>
|
||||
|
||||
@@ -17,8 +17,8 @@ import I18n from "I18n";
|
||||
import { translations } from "pretty-text/emoji/data";
|
||||
import { setupHashtagAutocomplete } from "discourse/lib/hashtag-autocomplete";
|
||||
import { isEmpty, isPresent } from "@ember/utils";
|
||||
import ChatMessage from "discourse/plugins/chat/discourse/models/chat-message";
|
||||
import { Promise } from "rsvp";
|
||||
import ChatMessage from "discourse/plugins/chat/discourse/models/chat-message";
|
||||
import User from "discourse/models/user";
|
||||
|
||||
export default class ChatComposer extends Component {
|
||||
@@ -33,6 +33,7 @@ export default class ChatComposer extends Component {
|
||||
@service chatEmojiPickerManager;
|
||||
@service currentUser;
|
||||
@service chatApi;
|
||||
@service chatDraftsManager;
|
||||
|
||||
@tracked isFocused = false;
|
||||
@tracked inProgressUploadsCount = 0;
|
||||
@@ -78,15 +79,8 @@ export default class ChatComposer extends Component {
|
||||
}
|
||||
|
||||
@action
|
||||
sendMessage(raw) {
|
||||
const message = ChatMessage.createDraftMessage(this.args.channel, {
|
||||
user: this.currentUser,
|
||||
message: raw,
|
||||
});
|
||||
|
||||
this.args.onSendMessage(message);
|
||||
|
||||
return Promise.resolve();
|
||||
sendMessage() {
|
||||
this.args.onSendMessage(this.currentMessage);
|
||||
}
|
||||
|
||||
@action
|
||||
@@ -107,13 +101,15 @@ export default class ChatComposer extends Component {
|
||||
|
||||
@action
|
||||
didUpdateMessage() {
|
||||
cancel(this._persistHandler);
|
||||
this.cancelPersistDraft();
|
||||
this.textareaInteractor.value = this.currentMessage.message || "";
|
||||
this.textareaInteractor.focus({ refreshHeight: true });
|
||||
this.persistDraft();
|
||||
}
|
||||
|
||||
@action
|
||||
didUpdateInReplyTo() {
|
||||
this.cancelPersistDraft();
|
||||
this.textareaInteractor.focus({ ensureAtEnd: true, refreshHeight: true });
|
||||
this.persistDraft();
|
||||
}
|
||||
@@ -148,11 +144,21 @@ export default class ChatComposer extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
@action
|
||||
didUpdateChannel() {
|
||||
if (!this.args.channel) {
|
||||
this.composer.message = null;
|
||||
}
|
||||
|
||||
this.composer.message =
|
||||
this.chatDraftsManager.get({ channelId: this.args.channel.id }) ||
|
||||
ChatMessage.createDraftMessage(this.args.channel, {
|
||||
user: this.currentUser,
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
setup() {
|
||||
this.composer.message = ChatMessage.createDraftMessage(this.args.channel, {
|
||||
user: this.currentUser,
|
||||
});
|
||||
this.appEvents.on("chat:modify-selection", this, "modifySelection");
|
||||
this.appEvents.on(
|
||||
"chat:open-insert-link-modal",
|
||||
|
||||
@@ -7,6 +7,7 @@ import { action } from "@ember/object";
|
||||
export default class ChatComposerChannel extends ChatComposer {
|
||||
@service("chat-channel-composer") composer;
|
||||
@service("chat-channel-pane") pane;
|
||||
@service chatDraftsManager;
|
||||
|
||||
context = "channel";
|
||||
|
||||
@@ -23,6 +24,8 @@ export default class ChatComposerChannel extends ChatComposer {
|
||||
return;
|
||||
}
|
||||
|
||||
this.chatDraftsManager.add(this.currentMessage);
|
||||
|
||||
this._persistHandler = discourseDebounce(
|
||||
this,
|
||||
this._debouncedPersistDraft,
|
||||
|
||||
@@ -81,7 +81,6 @@ export default class ChatChannel {
|
||||
@tracked canFlag;
|
||||
@tracked canModerate;
|
||||
@tracked userSilenced;
|
||||
@tracked draft = null;
|
||||
@tracked meta;
|
||||
@tracked chatableType;
|
||||
@tracked chatableUrl;
|
||||
|
||||
@@ -138,8 +138,12 @@ export default class ChatMessage {
|
||||
}
|
||||
|
||||
cook() {
|
||||
const site = getOwner(this).lookup("service:site");
|
||||
|
||||
next(() => {
|
||||
const site = getOwner(this).lookup("service:site");
|
||||
if (this.isDestroyed || this.isDestroying) {
|
||||
return;
|
||||
}
|
||||
|
||||
const markdownOptions = {
|
||||
featuresOverride:
|
||||
@@ -248,6 +252,12 @@ export default class ChatMessage {
|
||||
};
|
||||
}
|
||||
|
||||
if (this.editing) {
|
||||
data.editing = true;
|
||||
data.id = this.id;
|
||||
data.excerpt = this.excerpt;
|
||||
}
|
||||
|
||||
return JSON.stringify(data);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
import { inject as service } from "@ember/service";
|
||||
import { action } from "@ember/object";
|
||||
import ChatComposer from "./chat-composer";
|
||||
import ChatMessage from "discourse/plugins/chat/discourse/models/chat-message";
|
||||
|
||||
export default class ChatChannelComposer extends ChatComposer {
|
||||
@service chat;
|
||||
@service router;
|
||||
|
||||
@action
|
||||
reset(channel) {
|
||||
this.message = ChatMessage.createDraftMessage(channel, {
|
||||
user: this.currentUser,
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
replyTo(message) {
|
||||
this.chat.activeMessage = null;
|
||||
|
||||
@@ -7,7 +7,7 @@ export default class ChatChannelThreadComposer extends ChatComposer {
|
||||
reset(channel, thread) {
|
||||
this.message = ChatMessage.createDraftMessage(channel, {
|
||||
user: this.currentUser,
|
||||
thread,
|
||||
});
|
||||
this.message.thread = thread;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import Service, { inject as service } from "@ember/service";
|
||||
import { action } from "@ember/object";
|
||||
import ChatMessage from "discourse/plugins/chat/discourse/models/chat-message";
|
||||
|
||||
export default class ChatComposer extends Service {
|
||||
@service chat;
|
||||
@service currentUser;
|
||||
|
||||
@tracked _message;
|
||||
@tracked message;
|
||||
|
||||
@action
|
||||
cancel() {
|
||||
@@ -18,13 +17,6 @@ export default class ChatComposer extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
reset(channel) {
|
||||
this.message = ChatMessage.createDraftMessage(channel, {
|
||||
user: this.currentUser,
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
clear() {
|
||||
this.message.message = "";
|
||||
@@ -41,12 +33,4 @@ export default class ChatComposer extends Service {
|
||||
onCancelEditing() {
|
||||
this.reset();
|
||||
}
|
||||
|
||||
get message() {
|
||||
return this._message;
|
||||
}
|
||||
|
||||
set message(message) {
|
||||
this._message = message;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import Service from "@ember/service";
|
||||
import ChatMessage from "discourse/plugins/chat/discourse/models/chat-message";
|
||||
export default class ChatDraftsManager extends Service {
|
||||
drafts = {};
|
||||
|
||||
add(message) {
|
||||
if (message instanceof ChatMessage) {
|
||||
this.drafts[message.channel.id] = message;
|
||||
} else {
|
||||
throw new Error("message must be an instance of ChatMessage");
|
||||
}
|
||||
}
|
||||
|
||||
get({ channelId }) {
|
||||
return this.drafts[channelId];
|
||||
}
|
||||
|
||||
remove({ channelId }) {
|
||||
delete this.drafts[channelId];
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.drafts = {};
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ export default class Chat extends Service {
|
||||
@service chatNotificationManager;
|
||||
@service chatSubscriptionsManager;
|
||||
@service chatStateManager;
|
||||
@service chatDraftsManager;
|
||||
@service presence;
|
||||
@service router;
|
||||
@service site;
|
||||
@@ -167,19 +168,18 @@ export default class Chat extends Service {
|
||||
[...channels.public_channels, ...channels.direct_message_channels].forEach(
|
||||
(channelObject) => {
|
||||
const channel = this.chatChannelsManager.store(channelObject);
|
||||
const storedDraft = (this.currentUser?.chat_drafts || []).find(
|
||||
(draft) => draft.channel_id === channel.id
|
||||
);
|
||||
|
||||
if (this.currentUser.chat_drafts) {
|
||||
const storedDraft = this.currentUser.chat_drafts.find(
|
||||
(draft) => draft.channel_id === channel.id
|
||||
);
|
||||
|
||||
channel.draft = ChatMessage.createDraftMessage(
|
||||
channel,
|
||||
Object.assign(
|
||||
{
|
||||
user: this.currentUser,
|
||||
},
|
||||
storedDraft ? JSON.parse(storedDraft.data) : {}
|
||||
if (storedDraft) {
|
||||
this.chatDraftsManager.add(
|
||||
ChatMessage.createDraftMessage(
|
||||
channel,
|
||||
Object.assign(
|
||||
{ user: this.currentUser },
|
||||
JSON.parse(storedDraft.data)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user