FIX: improvements to chat message streaming (#26892)

- prevents re-rendering avatars while updating messages quickly in the thread preview indicator
- ensures the cancel button is shown when you are admin OR when the streamed message is a reply to the current user
This commit is contained in:
Joffrey JAFFEUX 2024-05-07 15:38:24 +02:00 committed by GitHub
parent 42297b2ec3
commit 278eb0a1a5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 82 additions and 11 deletions

View File

@ -492,7 +492,7 @@ export default class ChatMessage extends Component {
return (
this.args.message.streaming &&
(this.currentUser.admin ||
this.args.message.user.id === this.currentUser.id)
this.args.message.inReplyTo?.user?.id === this.currentUser.id)
);
}

View File

@ -234,7 +234,11 @@ export default class ChatChannelSubscriptionManager {
handleThreadOriginalMessageUpdate(data) {
const message = this.messagesManager.findMessage(data.original_message_id);
if (message?.thread) {
message.thread.preview = ChatThreadPreview.create(data.preview);
if (message.thread.preview) {
message.thread.preview.update(data.preview);
} else {
message.thread.preview = ChatThreadPreview.create(data.preview);
}
}
}
}

View File

@ -1,5 +1,4 @@
import { tracked } from "@glimmer/tracking";
import { TrackedArray } from "@ember-compat/tracked-built-ins";
export default class ChatThreadPreview {
static create(args = {}) {
@ -19,21 +18,37 @@ export default class ChatThreadPreview {
args = {};
}
this.update(args);
}
get otherParticipantCount() {
return this.participantCount - this.participantUsers.length;
}
update(args = {}) {
this.replyCount = args.reply_count || args.replyCount || 0;
this.lastReplyId = args.last_reply_id || args.lastReplyId;
this.lastReplyCreatedAt = new Date(
args.last_reply_created_at || args.lastReplyCreatedAt
);
this.lastReplyExcerpt = args.last_reply_excerpt || args.lastReplyExcerpt;
this.lastReplyUser = args.last_reply_user || args.lastReplyUser;
this.participantCount =
args.participant_count || args.participantCount || 0;
this.participantUsers = new TrackedArray(
args.participant_users || args.participantUsers || []
);
}
get otherParticipantCount() {
return this.participantCount - this.participantUsers.length;
// cheap trick to avoid avatars flickering
const lastReplyUser = args.last_reply_user || args.lastReplyUser;
if (lastReplyUser?.id !== this.lastReplyUser?.id) {
this.lastReplyUser = lastReplyUser;
}
// cheap trick to avoid avatars flickering
const participantUsers =
args.participant_users || args.participantUsers || [];
if (
participantUsers?.map((u) => u.id).join(",") !==
this.participantUsers?.map((u) => u.id).join(",")
) {
this.participantUsers = participantUsers;
}
}
}

View File

@ -1,5 +1,5 @@
import { getOwner } from "@ember/application";
import { render } from "@ember/test-helpers";
import { clearRender, render } from "@ember/test-helpers";
import hbs from "htmlbars-inline-precompile";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
@ -58,4 +58,56 @@ module("Discourse Chat | Component | chat-message", function (hooks) {
"has the correct css class"
);
});
test("Message with streaming", async function (assert) {
// admin
this.currentUser.admin = true;
this.message = new ChatFabricators(getOwner(this)).message({
inReplyTo: new ChatFabricators(getOwner(this)).message(),
streaming: true,
});
await this.message.cook();
await render(template);
assert
.dom(".stop-streaming-btn")
.exists("when admin, it has the stop streaming button");
await clearRender();
// not admin - not replying to current user
this.currentUser.admin = false;
this.message = new ChatFabricators(getOwner(this)).message({
inReplyTo: new ChatFabricators(getOwner(this)).message(),
streaming: true,
});
await this.message.cook();
await render(template);
assert
.dom(".stop-streaming-btn")
.doesNotExist("when admin, it doesn't have the stop streaming button");
await clearRender();
// not admin - replying to current user
this.currentUser.admin = false;
this.message = new ChatFabricators(getOwner(this)).message({
inReplyTo: new ChatFabricators(getOwner(this)).message({
user: this.currentUser,
}),
streaming: true,
});
await this.message.cook();
await render(template);
assert
.dom(".stop-streaming-btn")
.exists(
"when replying to current user, it has the stop streaming button"
);
});
});