From 25c0b279f748e8a82058a02a1122bab41fbfb704 Mon Sep 17 00:00:00 2001 From: Evy Kassirer Date: Thu, 8 May 2025 11:32:48 +0200 Subject: [PATCH] invite: Fetch full user set for get_unique_subscriber_count_for_streams. Work towards #34244. --- web/src/invite.ts | 19 ++++++++++--------- web/src/peer_data.ts | 17 +++++++++++++++-- web/styles/zulip.css | 8 ++++++++ web/templates/guest_visible_users_message.hbs | 8 +++++++- web/templates/invite_user_modal.hbs | 1 + web/tests/peer_data.test.cjs | 4 ++-- 6 files changed, 43 insertions(+), 14 deletions(-) diff --git a/web/src/invite.ts b/web/src/invite.ts index f6bfb8e9b0..b2252ea6dc 100644 --- a/web/src/invite.ts +++ b/web/src/invite.ts @@ -5,7 +5,6 @@ import assert from "minimalistic-assert"; import {z} from "zod"; import render_copy_invite_link from "../templates/copy_invite_link.hbs"; -import render_guest_visible_users_message from "../templates/guest_visible_users_message.hbs"; import render_invitation_failed_error from "../templates/invitation_failed_error.hbs"; import render_invite_user_modal from "../templates/invite_user_modal.hbs"; import render_invite_tips_banner from "../templates/modal_banner/invite_tips_banner.hbs"; @@ -21,6 +20,7 @@ import * as dialog_widget from "./dialog_widget.ts"; import * as email_pill from "./email_pill.ts"; import {$t, $t_html} from "./i18n.ts"; import * as invite_stream_picker_pill from "./invite_stream_picker_pill.ts"; +import * as loading from "./loading.ts"; import {page_params} from "./page_params.ts"; import * as peer_data from "./peer_data.ts"; import * as settings_components from "./settings_components.ts"; @@ -301,7 +301,7 @@ function set_streams_to_join_list_visibility(): void { } } -function update_guest_visible_users_count_and_stream_ids(): void { +async function update_guest_visible_users_count_and_stream_ids(): Promise { const invite_as = Number.parseInt( $("select:not([multiple])#invite_as").val()!, 10, @@ -320,13 +320,14 @@ function update_guest_visible_users_count_and_stream_ids(): void { const stream_ids = $("#invite_select_default_streams").is(":checked") ? stream_data.get_default_stream_ids() : stream_pill.get_stream_ids(stream_pill_widget); - const visible_users_count = peer_data.get_unique_subscriber_count_for_streams(stream_ids); - const message_html = render_guest_visible_users_message({ - user_count: visible_users_count, - }); + $(".guest-visible-users-count").empty(); + loading.make_indicator($(".guest_visible_users_loading")); + $("#guest_visible_users_container").show(); - $("#guest_visible_users_container").html(message_html).show(); + const visible_users_count = await peer_data.get_unique_subscriber_count_for_streams(stream_ids); + $(".guest-visible-users-count").text(visible_users_count); + loading.destroy_indicator($(".guest_visible_users_loading")); } function generate_invite_tips_data(): Record { @@ -415,12 +416,12 @@ function open_invite_user_modal(e: JQuery.ClickEvent): void $("#invite_streams_container .input, #invite_select_default_streams").on( "change", - update_guest_visible_users_count_and_stream_ids, + () => void update_guest_visible_users_count_and_stream_ids(), ); $("#invite_as").on("change", () => { update_stream_list(); - update_guest_visible_users_count_and_stream_ids(); + void update_guest_visible_users_count_and_stream_ids(); }); $("#invite-user-modal").on("click", ".setup-tips-container .banner_content a", () => { diff --git a/web/src/peer_data.ts b/web/src/peer_data.ts index a617188a2f..bf21e1117a 100644 --- a/web/src/peer_data.ts +++ b/web/src/peer_data.ts @@ -112,6 +112,11 @@ function get_loaded_subscriber_subset(stream_id: number): LazySet { return subscribers; } +async function get_full_subscriber_set(stream_id: number, retry_on_failure: true): Promise; +async function get_full_subscriber_set( + stream_id: number, + retry_on_failure: boolean, +): Promise; async function get_full_subscriber_set( stream_id: number, retry_on_failure: boolean, @@ -317,11 +322,19 @@ export async function maybe_fetch_is_user_subscribed( return subscribers.has(user_id); } -export function get_unique_subscriber_count_for_streams(stream_ids: number[]): number { +export async function get_unique_subscriber_count_for_streams( + stream_ids: number[], +): Promise { const valid_subscribers = new LazySet([]); + const promises: Record> = {}; + for (const stream_id of stream_ids) { + promises[stream_id] = get_full_subscriber_set(stream_id, true); + } for (const stream_id of stream_ids) { - const subscribers = get_loaded_subscriber_subset(stream_id); + // If it's `null`, that means a request failed and we don't know the + // full subscribers set, so just use whatever we have already. + const subscribers = await promises[stream_id]!; for (const user_id of subscribers.keys()) { if (!people.is_valid_bot_user(user_id)) { diff --git a/web/styles/zulip.css b/web/styles/zulip.css index c973015115..ec8cd091cd 100644 --- a/web/styles/zulip.css +++ b/web/styles/zulip.css @@ -1326,6 +1326,14 @@ div.toggle_resolve_topic_spinner .loading_indicator_spinner { vertical-align: bottom; } +#invite-user-form .loading_indicator_spinner { + height: 1em; + width: fit-content; + display: inline-block; + float: none; + margin: 0 5px; +} + .add-user-group-container, .add_streams_container { display: inline-flex; diff --git a/web/templates/guest_visible_users_message.hbs b/web/templates/guest_visible_users_message.hbs index 293cf137f6..e3a44808be 100644 --- a/web/templates/guest_visible_users_message.hbs +++ b/web/templates/guest_visible_users_message.hbs @@ -1,4 +1,10 @@

- {{t 'Guests will be able to see {user_count} users in their channels when they join.'}} + {{#tr}} + Guests will be able to see users in their channels when they join. + {{#*inline "z-user-count"}} + + + {{/inline}} + {{/tr}} {{> help_link_widget link="/help/guest-users#configure-whether-guests-can-see-all-other-users" }}

diff --git a/web/templates/invite_user_modal.hbs b/web/templates/invite_user_modal.hbs index 36a7433598..a3dc40aead 100644 --- a/web/templates/invite_user_modal.hbs +++ b/web/templates/invite_user_modal.hbs @@ -85,6 +85,7 @@ {{#if show_group_pill_container}}
diff --git a/web/tests/peer_data.test.cjs b/web/tests/peer_data.test.cjs index 06312ee4ce..a0e542a167 100644 --- a/web/tests/peer_data.test.cjs +++ b/web/tests/peer_data.test.cjs @@ -447,7 +447,7 @@ test("is_subscriber_subset", async () => { assert.equal(await peer_data.is_subscriber_subset(sub_a.stream_id, sub_b.stream_id), null); }); -test("get_unique_subscriber_count_for_streams", () => { +test("get_unique_subscriber_count_for_streams", async () => { const sub = {name: "Rome", subscribed: true, stream_id: 1001}; stream_data.add_sub(sub); @@ -459,7 +459,7 @@ test("get_unique_subscriber_count_for_streams", () => { const stream_id = sub.stream_id; peer_data.set_subscribers(stream_id, [me.user_id, fred.user_id, bot_botson.user_id]); - const count = peer_data.get_unique_subscriber_count_for_streams([stream_id]); + const count = await peer_data.get_unique_subscriber_count_for_streams([stream_id]); assert.equal(count, 2); });