FIX: auto fill was not happening on first load (#21809)

This commit attempts to fix the case where the messages loaded initially don't fill the screen. It would prevent user to scroll and as a result to load more.

There are multiple fixes in this commit:
- the main fix is removing this code which was preventing the actual fill:

```javascript
        // prevents an edge case where user clicks bottom arrow
        // just after scrolling to top
        if (loadingPast && this.#isAtBottom()) {
          return;
        }
```

- ensures we always give a page site to the `chatApi.channel(...)` call if we have one, in the current state when `fetchFromLastRead` was `true` we would not set `args.page_size`
- ensures the `query_paginated_messages` is having a valid page size, which is not nil and not > `MAX_PAGE_SIZE`
- write a spec for the autofill, it was a challenging spec to write but it should give us the confidence we need here
This commit is contained in:
Joffrey JAFFEUX 2023-05-29 17:34:44 +02:00 committed by GitHub
parent 4198ac43b4
commit 55ef2d0698
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 70 additions and 57 deletions

View File

@ -125,6 +125,8 @@ module Chat
messages,
target_message_id = nil
)
page_size = [page_size || MAX_PAGE_SIZE, MAX_PAGE_SIZE].min
if target_message_id.present?
condition = direction == PAST ? "<" : ">"
messages = messages.where("id #{condition} ?", target_message_id.to_i)

View File

@ -94,7 +94,7 @@ export default class ChatLivePane extends Component {
@action
didResizePane() {
this.fillPaneAttempt();
this.debounceFillPaneAttempt();
this.computeDatesSeparators();
this.forceRendering();
}
@ -228,7 +228,7 @@ export default class ChatLivePane extends Component {
this.loadedOnce = true;
this.requestedTargetMessageId = null;
this.loadingMorePast = false;
this.fillPaneAttempt();
this.debounceFillPaneAttempt();
this.updateLastReadMessage();
this.subscribeToUpdates(this.args.channel);
});
@ -276,12 +276,6 @@ export default class ChatLivePane extends Component {
return;
}
// prevents an edge case where user clicks bottom arrow
// just after scrolling to top
if (loadingPast && this.#isAtBottom()) {
return;
}
const [messages, meta] = this.afterFetchCallback(
this.args.channel,
result
@ -318,11 +312,23 @@ export default class ChatLivePane extends Component {
.catch(this._handleErrors)
.finally(() => {
this[loadingMoreKey] = false;
this.fillPaneAttempt();
this.debounceFillPaneAttempt();
});
}
@debounce(500)
debounceFillPaneAttempt() {
if (!this.loadedOnce) {
return;
}
this._debouncedFillPaneAttemptHandler = discourseDebounce(
this,
this.fillPaneAttempt,
500
);
}
@bind
fillPaneAttempt() {
if (this._selfDeleted) {
return;
@ -333,11 +339,12 @@ export default class ChatLivePane extends Component {
return;
}
if (!this.args.channel?.messagesManager?.canLoadMorePast) {
if (!this.args.channel?.canLoadMorePast) {
return;
}
const firstMessage = this.args.channel?.messages?.[0];
const firstMessage = this.args.channel?.messages?.firstObject;
if (!firstMessage?.visible) {
return;
}
@ -1055,6 +1062,7 @@ export default class ChatLivePane extends Component {
}
#cancelHandlers() {
cancel(this._debouncedFillPaneAttemptHandler);
cancel(this._onScrollEndedHandler);
cancel(this._laterComputeHandler);
cancel(this._debounceFetchMessagesHandler);

View File

@ -24,14 +24,13 @@ export default class ChatApi extends Service {
*/
channel(channelId, data = {}) {
const args = {};
args.page_size = data.pageSize;
if (data.targetMessageId) {
args.target_message_id = data.targetMessageId;
} else if (data.fetchFromLastRead) {
args.fetch_from_last_read = true;
} else {
args.page_size = data.pageSize;
if (data.direction) {
args.direction = data.direction;
}

View File

@ -71,6 +71,11 @@ RSpec.describe Chat::MessagesQuery do
end
end
it "limits results of paginated query when page_size is not set" do
options[:target_message_id] = nil
stub_const(described_class, "MAX_PAGE_SIZE", 1) { expect(subject[:messages].length).to eq(1) }
end
describe "when some messages are in threads" do
fab!(:thread) { Fabricate(:chat_thread, channel: channel) }

View File

@ -7,15 +7,41 @@ RSpec.describe "Chat channel", type: :system, js: true do
let(:chat) { PageObjects::Pages::Chat.new }
let(:channel_page) { PageObjects::Pages::ChatChannel.new }
let(:sidebar_page) { PageObjects::Pages::Sidebar.new }
before { chat_system_bootstrap }
before do
chat_system_bootstrap
channel_1.add(current_user)
sign_in(current_user)
end
context "when sending a message" do
context "when first batch of messages doesnt fill page" do
before do
channel_1.add(current_user)
sign_in(current_user)
50.times do
Fabricate(
:chat_message,
message: Faker::Lorem.characters(number: SiteSetting.chat_minimum_message_length),
user: current_user,
chat_channel: channel_1,
)
end
end
it "autofills for more messages" do
chat.prefers_full_page
visit("/")
# cheap trick to ensure the messages don't fill the initial page
page.execute_script(
"document.head.insertAdjacentHTML('beforeend', `<style>.chat-message-text{font-size:3px;}</style>`)",
)
sidebar_page.open_channel(channel_1)
expect(channel_page).to have_no_loading_skeleton
expect(channel_page.messages).to have_x_messages(51)
end
end
context "when sending a message" do
context "with lots of messages" do
before { 50.times { Fabricate(:chat_message, chat_channel: channel_1) } }
@ -71,11 +97,7 @@ RSpec.describe "Chat channel", type: :system, js: true do
end
context "when clicking the arrow button" do
before do
channel_1.add(current_user)
50.times { Fabricate(:chat_message, chat_channel: channel_1) }
sign_in(current_user)
end
before { 50.times { Fabricate(:chat_message, chat_channel: channel_1) } }
it "jumps to the bottom of the channel" do
unloaded_message = Fabricate(:chat_message, chat_channel: channel_1)
@ -92,11 +114,6 @@ RSpec.describe "Chat channel", type: :system, js: true do
end
context "when returning to a channel where last read is not last message" do
before do
channel_1.add(current_user)
sign_in(current_user)
end
it "jumps to the bottom of the channel" do
channel_1.membership_for(current_user).update!(last_read_message: message_1)
messages = 50.times.map { Fabricate(:chat_message, chat_channel: channel_1) }
@ -112,9 +129,7 @@ RSpec.describe "Chat channel", type: :system, js: true do
before do
channel_1.add(other_user)
channel_1.add(current_user)
50.times { Fabricate(:chat_message, chat_channel: channel_1) }
sign_in(current_user)
end
it "doesnt scroll the pane" do
@ -142,11 +157,7 @@ RSpec.describe "Chat channel", type: :system, js: true do
)
end
before do
channel_1.add(other_user)
channel_1.add(current_user)
sign_in(current_user)
end
before { channel_1.add(other_user) }
it "highlights the mentions" do
chat.visit_channel(channel_1)
@ -185,8 +196,6 @@ RSpec.describe "Chat channel", type: :system, js: true do
before do
Fabricate(:chat_message, in_reply_to: message_1, user: other_user, chat_channel: channel_1)
channel_1.add(other_user)
channel_1.add(current_user)
sign_in(current_user)
end
it "doesnt show the reply-to line" do
@ -203,8 +212,6 @@ RSpec.describe "Chat channel", type: :system, js: true do
Fabricate(:chat_message, user: other_user, chat_channel: channel_1)
Fabricate(:chat_message, in_reply_to: message_1, user: other_user, chat_channel: channel_1)
channel_1.add(other_user)
channel_1.add(current_user)
sign_in(current_user)
end
it "shows the reply-to line" do
@ -229,8 +236,6 @@ RSpec.describe "Chat channel", type: :system, js: true do
Fabricate(:chat_message, user: other_user, chat_channel: channel_1)
Fabricate(:chat_message, in_reply_to: message_2, user: current_user, chat_channel: channel_1)
channel_1.add(other_user)
channel_1.add(current_user)
sign_in(current_user)
end
it "renders text in the reply-to" do
@ -241,12 +246,7 @@ RSpec.describe "Chat channel", type: :system, js: true do
end
context "when messages are separated by a day" do
before do
Fabricate(:chat_message, chat_channel: channel_1, created_at: 2.days.ago)
channel_1.add(current_user)
sign_in(current_user)
end
before { Fabricate(:chat_message, chat_channel: channel_1, created_at: 2.days.ago) }
it "shows a date separator" do
chat.visit_channel(channel_1)
@ -264,11 +264,6 @@ RSpec.describe "Chat channel", type: :system, js: true do
\`\`\`
MESSAGE
before do
channel_1.add(current_user)
sign_in(current_user)
end
it "adds the correct lang" do
chat.visit_channel(channel_1)
@ -277,11 +272,7 @@ RSpec.describe "Chat channel", type: :system, js: true do
end
context "when scrolling" do
before do
channel_1.add(current_user)
50.times { Fabricate(:chat_message, chat_channel: channel_1) }
sign_in(current_user)
end
before { 50.times { Fabricate(:chat_message, chat_channel: channel_1) } }
it "resets the active message" do
chat.visit_channel(channel_1)

View File

@ -12,6 +12,10 @@ module PageObjects
@context = context
end
def component
find(context)
end
def has_message?(**args)
PageObjects::Components::Chat::Message.new(".chat-channel").exists?(**args)
end
@ -19,6 +23,10 @@ module PageObjects
def has_no_message?(**args)
!has_message?(**args)
end
def has_x_messages?(count)
find(context).has_css?(SELECTOR, count: count, visible: :all)
end
end
end
end