Skip to content

Conversation

chrisbobbe
Copy link
Collaborator

@chrisbobbe chrisbobbe commented Sep 25, 2025

Stacked atop #1871.


This fixes part of the "second buggy behavior" that I described
in #1789: specifically, it fixes that behavior when the self-user
doesn't have permission to send messages in the channel.

Later, for the case where there is permission to send messages, we
should use a different banner label, like "Replies to your messages
will not appear automatically." I think it's smoothest not to touch
that case until we've fixed the "first" and "third" parts of #1798,
because those are bugs in the send-message experience.

Fixes-partly: #1798

@chrisbobbe chrisbobbe added the maintainer review PR ready for review by Zulip maintainers label Sep 25, 2025
@chrisbobbe
Copy link
Collaborator Author

Before (well, after #1871) After
image image
image image

Copy link
Member

@rajveermalviya rajveermalviya left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @chrisbobbe! LGTM and tests great. Moving over to Greg's review.

(I also see that this needs a rebase, as the base PR has been update with new commits).

@rajveermalviya rajveermalviya added integration review Added by maintainers when PR may be ready for integration and removed maintainer review PR ready for review by Zulip maintainers labels Sep 30, 2025
We're about to use this more; seems a good time to write a test.
…send

This fixes part of the "second buggy behavior" that I described
in zulip#1789: specifically, it fixes that behavior when the self-user
doesn't have permission to send messages in the channel.

Later, for the case where there *is* permission to send messages, we
should use a different banner label, like "Replies to your messages
will not appear automatically." I think it's smoothest not to touch
that case until we've fixed the "first" and "third" parts of zulip#1798,
because those are bugs in the send-message experience.

Fixes-partly: zulip#1798
@chrisbobbe chrisbobbe force-pushed the pr-refresh-subscribe-when-cannot-send branch from b34b3a8 to 34fd9e5 Compare October 1, 2025 22:40
@chrisbobbe
Copy link
Collaborator Author

I also see that this needs a rebase

Done.

Copy link
Member

@gnprice gnprice left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for building this! Comments below.

Should also get a UX review from Alya (unless there already was one in a chat thread, not sure).

Comment on lines +440 to +447
// …do something unrelated…
connection.prepare(json: olderResult(
anchor: 1000, foundOldest: false,
messages: List.generate(100,
(i) => eg.streamMessage(id: 900 + i, stream: channel)),
).toJson());
await model.fetchOlder();
checkNotified(count: 2);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the role of this step in the narrative of the test? It feels like it'd all work the same way without this.

model.renarrowAndFetch(newNarrow, newAnchor);
checkNotifiedOnce();
check(model)
..generation.equals(generationBefore + 1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally the generation would be an implementation detail of the view-model, not something a test inspects.

I think the substance of this check can be gotten by having a fetchOlder call like above, but delaying its result to come in after the renarrowAndFetch (and before the latter fetch completes). Then we can check that after the time the fetchOlder result would have arrived, the list is still empty.

Comment on lines +1832 to +1833
// TODO better to refetch around some visible message if any
MessageListPage.ancestorOf(pageContext).refresh(AnchorCode.newest);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This TODO appears at both call sites of the new MessageListPageState.refresh. It seems like functionality that naturally belongs inside that method — that widget is closer to the responsibility for managing which messages are visible than these buttons are.

});
}

doTestComposeBoxShown(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: "do" seems redundant; and this calls testWidgets, so corresponds to one test case, so it's helpful to use the same "testFoo" naming

byDate: DateTime.now())) {
return _ErrorBanner(getLabel: (zulipLocalizations) =>
zulipLocalizations.errorBannerCannotPostInChannelLabel);
return (channel == null || channel is Subscription)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This condition is a bit puzzling — it combines the two extremes of a spectrum of three cases, treating them the same yet differently from the middle case. Is that the intended behavior?

Comment on lines +1495 to +1500
doTestComposeBoxShown(
narrow: topicNarrow,
isChannelSubscribed: false,
channelPostPolicy: ChannelPostPolicy.administrators,
selfUserRole: UserRole.moderator,
expected: false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is kind of a lot of similar test cases — I think it makes it harder to see the overall picture.

Do we need 4 cases of a topic narrow? I think just one suffices, exercising a banner appearing instead of the compose box. That shows that we haven't forgotten to wire up topic narrows to this logic.

Comment on lines +1470 to +1471
channelPostPolicy: ChannelPostPolicy.moderators,
selfUserRole: UserRole.administrator,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then I think this pair of params could be summarized as a boolean named like canSend. That's all they're expressing, right? That'd reduce the complexity when reading each of these cases, and scanning over them.

delay: Duration(seconds: 1));
await tester.tap(find.widgetWithText(ZulipWebUiKitButton, 'Refresh'));
await tester.pump();
check(store.debugMessageListViews).single
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about:

Suggested change
check(store.debugMessageListViews).single
final model = MessageListPage.ancestorOf(state.context).model;
check(model)

then reuse model below.

(Oh and I guess do this a bit above, at the first reference to the model.)

@alya
Copy link
Collaborator

alya commented Oct 2, 2025

The screenshots look good to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
integration review Added by maintainers when PR may be ready for integration
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants