narrow-state: Add only_valid_id boolean param to stream_id function.

Updates narrow_state.stream_id to have a boolean parameter, that
defaults to false. When true, the function will return an ID or
undefined based on the stream data that we have. When false, the
function will return the operand of the channel narrow term when
it's a valid number or undefined if it's not.

Replaces all uses of narrow_state.stream_sub()?.stream_id to
instead use the updated stream_id function with only_valid_id set
to true.
This commit is contained in:
Lauryn Menard
2025-02-18 16:53:37 +01:00
committed by Tim Abbott
parent 4ab4b7d435
commit 51bb8eff59
5 changed files with 39 additions and 22 deletions

View File

@@ -363,7 +363,7 @@ function maybe_shrink_list(
// We want to always show PM recipients even if they're inactive.
const pm_ids_set = narrow_state.pm_ids_set();
const stream_id = narrow_state.stream_id();
const stream_id = narrow_state.stream_id(narrow_state.filter(), true);
const filter_by_stream_id =
stream_id &&
peer_data.get_subscriber_count(stream_id) <= max_channel_size_to_show_all_subscribers;
@@ -452,7 +452,7 @@ function get_filtered_user_id_list(
// We want to show subscribers even if they're inactive, if there are few
// enough subscribers in the channel.
const stream_id = narrow_state.stream_id();
const stream_id = narrow_state.stream_id(narrow_state.filter(), true);
if (stream_id) {
const subscribers = peer_data.get_subscribers(stream_id);
if (subscribers.length <= max_channel_size_to_show_all_subscribers) {

View File

@@ -53,7 +53,7 @@ export function get_recipient_label(message?: ComposeClosedMessage): RecipientLa
// For empty narrows where there's a clear reply target,
// i.e. stream+topic or a single direct message conversation,
// we label the button as replying to the thread.
const stream_id = narrow_state.stream_sub()?.stream_id;
const stream_id = narrow_state.stream_id(narrow_state.filter(), true);
const topic = narrow_state.topic();
if (stream_id !== undefined && topic !== undefined) {
return get_stream_recipient_label(stream_id, topic);

View File

@@ -100,12 +100,10 @@ export function set_compose_defaults(): {
// if they are uniquely specified in the narrow view.
if (single.has("channel")) {
// The raw stream name from collect_single may be an arbitrary
// unvalidated string from the URL fragment and thus not be valid.
// So we look up the resolved stream and return that if appropriate.
const sub = stream_sub();
if (sub !== undefined) {
opts.stream_id = sub.stream_id;
// Only set opts.stream_id if it is a valid stream ID.
const narrow_stream_id = stream_id(filter(), true);
if (narrow_stream_id !== undefined) {
opts.stream_id = narrow_stream_id;
}
}
@@ -124,7 +122,14 @@ export function set_compose_defaults(): {
return opts;
}
export let stream_id = (current_filter: Filter | undefined = filter()): number | undefined => {
export let stream_id = (
current_filter: Filter | undefined = filter(),
// If true, we'll return undefined if the filter contains a
// stream_id, but that stream ID is not present in stream_data
// (whether because it's an invalid channel ID, or because the
// channel is not accessible to this user).
only_valid_id = false,
): number | undefined => {
if (current_filter === undefined) {
return undefined;
}
@@ -132,7 +137,7 @@ export let stream_id = (current_filter: Filter | undefined = filter()): number |
if (stream_operands.length === 1 && stream_operands[0] !== undefined) {
const id = Number.parseInt(stream_operands[0], 10);
if (!Number.isNaN(id)) {
return id;
return only_valid_id ? stream_data.get_sub_by_id(id)?.stream_id : id;
}
}
return undefined;
@@ -261,7 +266,7 @@ export let _possible_unread_message_ids = (message_list_filter: Filter): number[
// If we do return a result, it will be a subset of unread
// message ids but possibly a superset of unread message ids
// that match our filter.
let filter_stream: StreamSubscription | undefined;
let filter_stream_id: number | undefined;
let topic_name: string | undefined;
let filter_pm_string: string | undefined;
@@ -283,20 +288,20 @@ export let _possible_unread_message_ids = (message_list_filter: Filter): number[
message_list_filter.can_bucket_by("channel", "topic", "with") ||
message_list_filter.can_bucket_by("channel", "topic")
) {
filter_stream = stream_sub(message_list_filter);
filter_stream_id = stream_id(message_list_filter, true);
topic_name = topic(message_list_filter);
if (filter_stream === undefined || topic_name === undefined) {
if (filter_stream_id === undefined || topic_name === undefined) {
return [];
}
return unread.get_msg_ids_for_topic(filter_stream.stream_id, topic_name);
return unread.get_msg_ids_for_topic(filter_stream_id, topic_name);
}
if (message_list_filter.can_bucket_by("channel")) {
filter_stream = stream_sub(message_list_filter);
if (filter_stream === undefined) {
filter_stream_id = stream_id(message_list_filter, true);
if (filter_stream_id === undefined) {
return [];
}
return unread.get_msg_ids_for_stream(filter_stream.stream_id);
return unread.get_msg_ids_for_stream(filter_stream_id);
}
if (

View File

@@ -177,7 +177,7 @@ export function update_stream_privacy(
// Update UI elements
update_left_panel_row(sub);
if (narrow_state.stream_sub()?.stream_id === sub.stream_id) {
if (narrow_state.stream_id(narrow_state.filter(), true) === sub.stream_id) {
// Rerender message list if we are narrowed to the stream.
message_lists.current?.rerender();
}

View File

@@ -50,11 +50,23 @@ test("stream", () => {
assert.equal(narrow_state.stream_sub(), undefined);
const test_stream_id = 15;
const test_stream = {name: "Test", stream_id: test_stream_id};
stream_data.add_sub(test_stream);
assert.ok(!narrow_state.narrowed_to_stream_id(test_stream_id));
// Stream doesn't exist or is inaccessible. The narrow
// does parse the channel operand as a valid number.
set_filter([["stream", test_stream_id.toString()]]);
assert.ok(narrow_state.filter());
// These do not check for stream subscription data.
assert.equal(narrow_state.stream_id(), test_stream_id);
assert.ok(narrow_state.narrowed_to_stream_id(test_stream_id));
// These do check for stream subscription data.
assert.equal(narrow_state.stream_name(), undefined);
assert.equal(narrow_state.stream_id(undefined, true), undefined);
assert.equal(narrow_state.stream_sub(), undefined);
// Stream exists and user has access to the stream.
const test_stream = {name: "Test", stream_id: test_stream_id};
stream_data.add_sub(test_stream);
set_filter([
["stream", test_stream_id.toString()],
["topic", "Bar"],