channel: Don't show "You subscribed to" bookend on channel creation.

Three events i.e. 'stream create', 'subscription add', and
'message' event are received by client on channel creation.

Earlier, we were narrowing to channel while processing the
'stream create' event. This was resulting in fetching messages
for that narrow even before adding subscription. This resulted
in a bug where "You subscribed to" bookend was visible in the
message feed after the "channel events" message.

This commit updates the logic to narrow ONLY after adding
subscription i.e. while processing "subscription add" event.

Note: A channel creator who is not going to subscribe to the
channel themselves is NOT narrowed to the channel view.

This fixes the incorrect behavior.
This commit is contained in:
Prakhar Pratyush 2024-07-02 13:37:50 +05:30 committed by Tim Abbott
parent 6c152b3adc
commit 909a2efb43
3 changed files with 87 additions and 29 deletions

View File

@ -1,10 +1,17 @@
import $ from "jquery";
import assert from "minimalistic-assert";
import render_inline_decorated_stream_name from "../templates/inline_decorated_stream_name.hbs";
import render_first_stream_created_modal from "../templates/stream_settings/first_stream_created_modal.hbs";
import * as activity_ui from "./activity_ui";
import * as blueslip from "./blueslip";
import * as browser_history from "./browser_history";
import * as color_data from "./color_data";
import * as compose_recipient from "./compose_recipient";
import * as dialog_widget from "./dialog_widget";
import * as hash_util from "./hash_util";
import {$t, $t_html} from "./i18n";
import * as message_lists from "./message_lists";
import * as message_view_header from "./message_view_header";
import * as narrow_state from "./narrow_state";
@ -14,6 +21,7 @@ import * as people from "./people";
import * as recent_view_ui from "./recent_view_ui";
import * as settings_notifications from "./settings_notifications";
import * as stream_color_events from "./stream_color_events";
import * as stream_create from "./stream_create";
import * as stream_data from "./stream_data";
import * as stream_list from "./stream_list";
import * as stream_muting from "./stream_muting";
@ -109,6 +117,23 @@ export function update_property(stream_id, property, value, other_values) {
}
}
function show_first_stream_created_modal(stream) {
dialog_widget.launch({
html_heading: $t_html(
{defaultMessage: "Channel <b><z-stream></z-stream></b> created!"},
{
"z-stream": () => render_inline_decorated_stream_name({stream}),
},
),
html_body: render_first_stream_created_modal({stream}),
id: "first_stream_created_modal",
on_click() {},
html_submit_button: $t({defaultMessage: "Continue"}),
close_on_submit: true,
single_footer_button: true,
});
}
// Add yourself to a stream we already know about client-side.
// It's likely we should be passing in the full sub object from the caller/backend,
// but for now we just pass in the subscribers and color (things likely to be different).
@ -146,6 +171,24 @@ export function mark_subscribed(sub, subscribers, color) {
// update navbar if necessary
message_view_header.maybe_rerender_title_area_for_stream(sub);
if (stream_create.get_name() === sub.name) {
// In this case, we just created this channel using this very
// browser window. We redirect the user to that channel so
// they can use the channel that they just created.
//
// It's important that we do this here, not in
// add_sub_to_table, to avoid showing or flashing a subscriber
// bookend during the window that the client doesn't yet know
// that we're a subscriber to the new channel.
stream_create.reset_created_stream();
browser_history.go_to_location(hash_util.by_stream_url(sub.stream_id));
if (stream_create.should_show_first_stream_created_modal()) {
stream_create.set_first_stream_created_modal_shown();
show_first_stream_created_modal(sub);
}
}
if (narrow_state.is_for_stream_id(sub.stream_id)) {
assert(message_lists.current !== undefined);
message_lists.current.update_trailing_bookend(true);

View File

@ -1,11 +1,9 @@
import $ from "jquery";
import _ from "lodash";
import render_inline_decorated_stream_name from "../templates/inline_decorated_stream_name.hbs";
import render_stream_creation_confirmation_banner from "../templates/modal_banner/stream_creation_confirmation_banner.hbs";
import render_browse_streams_list from "../templates/stream_settings/browse_streams_list.hbs";
import render_browse_streams_list_item from "../templates/stream_settings/browse_streams_list_item.hbs";
import render_first_stream_created_modal from "../templates/stream_settings/first_stream_created_modal.hbs";
import render_stream_settings from "../templates/stream_settings/stream_settings.hbs";
import render_stream_settings_overlay from "../templates/stream_settings/stream_settings_overlay.hbs";
@ -15,10 +13,9 @@ import * as components from "./components";
import * as compose_banner from "./compose_banner";
import * as compose_recipient from "./compose_recipient";
import * as compose_state from "./compose_state";
import * as dialog_widget from "./dialog_widget";
import * as hash_parser from "./hash_parser";
import * as hash_util from "./hash_util";
import {$t, $t_html} from "./i18n";
import {$t} from "./i18n";
import * as keydown_util from "./keydown_util";
import * as message_lists from "./message_lists";
import * as message_live_update from "./message_live_update";
@ -238,9 +235,13 @@ export function add_sub_to_table(sub) {
// stream was just created in this browser window; it's a hack
// to work around the server_events code flow not having a
// good way to associate with this request because the stream
// ID isn't known yet. These are appended to the top of the
// list, so they are more visible.
// ID isn't known to the client yet. These are appended to the
// top of the list, so they are more visible.
stream_ui_updates.row_for_stream_id(sub.stream_id).trigger("click");
// This banner is for administrators creating a channel that
// they are themselves not initial subscribers to; other users
// will be immediately navigated to the channel view.
const context = {
banner_type: compose_banner.SUCCESS,
classname: "stream_creation_confirmation",
@ -250,32 +251,9 @@ export function add_sub_to_table(sub) {
$("#stream_settings .stream-creation-confirmation-banner").html(
render_stream_creation_confirmation_banner(context),
);
stream_create.reset_created_stream();
// Go to the newly created stream interleaved view.
browser_history.go_to_location(hash_util.by_stream_url(sub.stream_id));
if (stream_create.should_show_first_stream_created_modal()) {
stream_create.set_first_stream_created_modal_shown();
show_first_stream_created_modal(sub);
}
}
update_empty_left_panel_message();
}
function show_first_stream_created_modal(stream) {
dialog_widget.launch({
html_heading: $t_html(
{defaultMessage: "Channel <b><z-stream></z-stream></b> created!"},
{
"z-stream": () => render_inline_decorated_stream_name({stream}),
},
),
html_body: render_first_stream_created_modal({stream}),
id: "first_stream_created_modal",
on_click() {},
html_submit_button: $t({defaultMessage: "Continue"}),
close_on_submit: true,
single_footer_button: true,
});
}
export function remove_stream(stream_id) {
// It is possible that row is empty when we deactivate a

View File

@ -8,12 +8,15 @@ const {run_test, noop} = require("./lib/test");
const blueslip = require("./lib/zblueslip");
const $ = require("./lib/zjquery");
const browser_history = mock_esm("../src/browser_history");
const color_data = mock_esm("../src/color_data");
const compose_recipient = mock_esm("../src/compose_recipient");
const dialog_widget = mock_esm("../src/dialog_widget");
const stream_color_events = mock_esm("../src/stream_color_events");
const stream_list = mock_esm("../src/stream_list");
const stream_muting = mock_esm("../src/stream_muting");
const stream_settings_api = mock_esm("../src/stream_settings_api");
const onboarding_steps = mock_esm("../src/onboarding_steps");
const stream_settings_ui = mock_esm("../src/stream_settings_ui", {
update_settings_for_subscribed: noop,
update_empty_left_panel_message: noop,
@ -43,6 +46,7 @@ const narrow_state = zrequire("narrow_state");
const peer_data = zrequire("peer_data");
const people = zrequire("people");
const settings_config = zrequire("settings_config");
const stream_create = zrequire("stream_create");
const stream_data = zrequire("stream_data");
const stream_events = zrequire("stream_events");
@ -486,3 +490,36 @@ test("process_subscriber_update", ({override, override_rewire}) => {
stream_events.process_subscriber_update(userIds, streamIds);
assert.ok(build_user_sidebar_called);
});
test("marked_subscribed (new channel creation)", ({override}) => {
stream_create.set_name(frontend.name);
const sub = {...frontend};
stream_data.add_sub(sub);
const go_to_location_stub = make_stub();
override(browser_history, "go_to_location", go_to_location_stub.f);
override(unread_ui, "update_unread_counts", noop);
override(stream_list, "add_sidebar_row", noop);
override(stream_list, "update_subscribe_to_more_streams_link", noop);
override(user_profile, "update_user_profile_streams_list_for_users", noop);
override(
onboarding_steps,
"ONE_TIME_NOTICES_TO_DISPLAY",
new Set(["first_stream_created_banner"]),
);
override(onboarding_steps, "post_onboarding_step_as_read", noop);
// We're stubbing 'dialog_widget.launch()' instead of
// 'stream_events.show_first_stream_created_modal()'
// as it helps in test coverage.
const dialog_widget_stub = make_stub();
override(dialog_widget, "launch", dialog_widget_stub.f);
stream_events.mark_subscribed(sub, [], "yellow");
// Verify that the creator is redirected to channel view
// and the first_stream_created modal is displayed.
assert.equal(go_to_location_stub.num_calls, 1);
assert.equal(dialog_widget_stub.num_calls, 1);
assert.equal(stream_create.get_name(), undefined);
});