hash_util: Set channel URL based on user setting.

We now render channel feed URL or channel topics list URL in
all elements based on user setting.
This commit is contained in:
Aman Agrawal
2025-05-02 16:15:23 +05:30
committed by Tim Abbott
parent 97c69e3038
commit 1ace8b80f5
23 changed files with 75 additions and 21 deletions

View File

@@ -28,3 +28,8 @@ declare export function by_stream_topic_url(
topic: string, topic: string,
maybe_get_stream_name: (id: number) => ?string, maybe_get_stream_name: (id: number) => ?string,
): string; ): string;
declare export function by_channel_topic_list_url(
stream_id: number,
maybe_get_stream_name: (id: number) => ?string,
): string;

View File

@@ -279,7 +279,7 @@ export function initialize(): void {
// so we re-encode the hash. // so we re-encode the hash.
const stream_id = Number.parseInt($(this).attr("data-stream-id")!, 10); const stream_id = Number.parseInt($(this).attr("data-stream-id")!, 10);
if (stream_id) { if (stream_id) {
browser_history.go_to_location(hash_util.by_stream_url(stream_id)); browser_history.go_to_location(hash_util.channel_url_by_user_setting(stream_id));
return; return;
} }
window.location.href = this.href; window.location.href = this.href;
@@ -436,6 +436,8 @@ export function initialize(): void {
} }
e.preventDefault(); e.preventDefault();
const row_id = get_row_id_for_narrowing(this); const row_id = get_row_id_for_narrowing(this);
// TODO: Navigate user according to `web_channel_default_view` setting.
// Also, update the tooltip hotkey in recipient bar.
message_view.narrow_by_recipient(row_id, {trigger: "message header"}); message_view.narrow_by_recipient(row_id, {trigger: "message header"});
}, },
); );

View File

@@ -4,6 +4,7 @@ import * as blueslip from "./blueslip.ts";
import type {Message} from "./message_store.ts"; import type {Message} from "./message_store.ts";
import {page_params} from "./page_params.ts"; import {page_params} from "./page_params.ts";
import * as people from "./people.ts"; import * as people from "./people.ts";
import {web_channel_default_view_values} from "./settings_config.ts";
import * as settings_data from "./settings_data.ts"; import * as settings_data from "./settings_data.ts";
import type {NarrowTerm} from "./state_data.ts"; import type {NarrowTerm} from "./state_data.ts";
import * as stream_data from "./stream_data.ts"; import * as stream_data from "./stream_data.ts";
@@ -12,6 +13,7 @@ import * as sub_store from "./sub_store.ts";
import type {StreamSubscription} from "./sub_store.ts"; import type {StreamSubscription} from "./sub_store.ts";
import * as user_groups from "./user_groups.ts"; import * as user_groups from "./user_groups.ts";
import type {UserGroup} from "./user_groups.ts"; import type {UserGroup} from "./user_groups.ts";
import {user_settings} from "./user_settings.ts";
import * as util from "./util.ts"; import * as util from "./util.ts";
export function build_reload_url(): string { export function build_reload_url(): string {
@@ -84,6 +86,16 @@ export function by_stream_url(stream_id: number): string {
return internal_url.by_stream_url(stream_id, sub_store.maybe_get_stream_name); return internal_url.by_stream_url(stream_id, sub_store.maybe_get_stream_name);
} }
export function channel_url_by_user_setting(channel_id: number): string {
if (
user_settings.web_channel_default_view ===
web_channel_default_view_values.list_of_topics.code
) {
return by_channel_topic_list_url(channel_id);
}
return by_stream_url(channel_id);
}
export function by_stream_topic_url(stream_id: number, topic: string): string { export function by_stream_topic_url(stream_id: number, topic: string): string {
// Wrapper for web use of internal_url.by_stream_topic_url // Wrapper for web use of internal_url.by_stream_topic_url
return internal_url.by_stream_topic_url(stream_id, topic, sub_store.maybe_get_stream_name); return internal_url.by_stream_topic_url(stream_id, topic, sub_store.maybe_get_stream_name);

View File

@@ -452,7 +452,7 @@ function format_stream(stream_id: number): StreamContext {
is_muted: stream_info.is_muted, is_muted: stream_info.is_muted,
stream_color: stream_color.get_stream_privacy_icon_color(stream_info.color), stream_color: stream_color.get_stream_privacy_icon_color(stream_info.color),
stream_header_color: stream_color.get_recipient_bar_color(stream_info.color), stream_header_color: stream_color.get_recipient_bar_color(stream_info.color),
stream_url: hash_util.by_stream_url(stream_id), stream_url: hash_util.channel_url_by_user_setting(stream_id),
stream_id, stream_id,
// Will be displayed if any topic is visible. // Will be displayed if any topic is visible.
is_hidden: true, is_hidden: true,

View File

@@ -76,7 +76,7 @@ export const get_helpers = (): MarkdownHelpers => ({
// stream hashes // stream hashes
get_stream_by_name: (name) => stream(stream_data.get_sub(name)), get_stream_by_name: (name) => stream(stream_data.get_sub(name)),
stream_hash: hash_util.by_stream_url, stream_hash: hash_util.channel_url_by_user_setting,
stream_topic_hash: hash_util.by_stream_topic_url, stream_topic_hash: hash_util.by_stream_topic_url,
// settings // settings

View File

@@ -383,7 +383,7 @@ function populate_group_from_message(
const topic_display_name = util.get_final_topic_display_name(topic); const topic_display_name = util.get_final_topic_display_name(topic);
const is_empty_string_topic = topic === ""; const is_empty_string_topic = topic === "";
const match_topic = util.get_match_topic(message); const match_topic = util.get_match_topic(message);
const stream_url = hash_util.by_stream_url(message.stream_id); const stream_url = hash_util.channel_url_by_user_setting(message.stream_id);
const is_archived = stream_data.is_stream_archived(message.stream_id); const is_archived = stream_data.is_stream_archived(message.stream_id);
const topic_url = internal_url.by_stream_topic_url( const topic_url = internal_url.by_stream_topic_url(
message.stream_id, message.stream_id,
@@ -815,7 +815,7 @@ export class MessageListView {
unsubscribed = false; unsubscribed = false;
if (message.type === "stream") { if (message.type === "stream") {
stream_url = hash_util.by_stream_url(message.stream_id); stream_url = hash_util.channel_url_by_user_setting(message.stream_id);
topic_url = hash_util.by_stream_topic_url(message.stream_id, message.topic); topic_url = hash_util.by_stream_topic_url(message.stream_id, message.topic);
} else { } else {
pm_with_url = message.pm_with_url; pm_with_url = message.pm_with_url;

View File

@@ -665,7 +665,7 @@ function format_conversation(conversation_data: ConversationData): ConversationC
const stream_id = last_msg.stream_id; const stream_id = last_msg.stream_id;
const stream_name = stream_data.get_stream_name_from_id(last_msg.stream_id); const stream_name = stream_data.get_stream_name_from_id(last_msg.stream_id);
const stream_color = stream_info.color; const stream_color = stream_info.color;
const stream_url = hash_util.by_stream_url(stream_id); const stream_url = hash_util.channel_url_by_user_setting(stream_id);
const invite_only = stream_info.invite_only; const invite_only = stream_info.invite_only;
const is_web_public = stream_info.is_web_public; const is_web_public = stream_info.is_web_public;
const is_archived = stream_info.is_archived; const is_archived = stream_info.is_archived;

View File

@@ -21,6 +21,7 @@ import * as emoji from "./emoji.ts";
import * as emoji_picker from "./emoji_picker.ts"; import * as emoji_picker from "./emoji_picker.ts";
import * as gear_menu from "./gear_menu.ts"; import * as gear_menu from "./gear_menu.ts";
import * as giphy from "./giphy.ts"; import * as giphy from "./giphy.ts";
import * as inbox_ui from "./inbox_ui.ts";
import * as information_density from "./information_density.ts"; import * as information_density from "./information_density.ts";
import * as left_sidebar_navigation_area from "./left_sidebar_navigation_area.ts"; import * as left_sidebar_navigation_area from "./left_sidebar_navigation_area.ts";
import * as linkifiers from "./linkifiers.ts"; import * as linkifiers from "./linkifiers.ts";
@@ -43,6 +44,7 @@ import * as realm_icon from "./realm_icon.ts";
import * as realm_logo from "./realm_logo.ts"; import * as realm_logo from "./realm_logo.ts";
import * as realm_playground from "./realm_playground.ts"; import * as realm_playground from "./realm_playground.ts";
import {realm_user_settings_defaults} from "./realm_user_settings_defaults.ts"; import {realm_user_settings_defaults} from "./realm_user_settings_defaults.ts";
import * as recent_view_ui from "./recent_view_ui.ts";
import * as reload from "./reload.ts"; import * as reload from "./reload.ts";
import * as saved_snippets from "./saved_snippets.ts"; import * as saved_snippets from "./saved_snippets.ts";
import * as saved_snippets_ui from "./saved_snippets_ui.ts"; import * as saved_snippets_ui from "./saved_snippets_ui.ts";
@@ -978,9 +980,19 @@ export function dispatch_normal_event(event) {
$("#automatically_offer_update_time_zone").prop("checked", event.value); $("#automatically_offer_update_time_zone").prop("checked", event.value);
} }
if (event.property === "web_channel_default_view") { if (event.property === "web_channel_default_view") {
// We need to rerender wherever `channel_url_by_user_setting` is used in the DOM.
// Left sidebar
const force_rerender = true; const force_rerender = true;
stream_list.create_initial_sidebar_rows(force_rerender); stream_list.create_initial_sidebar_rows(force_rerender);
stream_list.update_streams_sidebar(force_rerender); stream_list.update_streams_sidebar(force_rerender);
// Inbox View
inbox_ui.complete_rerender();
// Recent View
recent_view_ui.complete_rerender();
// Message feed
for (const msg_list of message_lists.all_rendered_message_lists()) {
msg_list.rerender();
}
} }
settings_preferences.update_page(event.property); settings_preferences.update_page(event.property);
break; break;

View File

@@ -288,7 +288,7 @@ export function mark_subscribed(
// bookend during the window that the client doesn't yet know // bookend during the window that the client doesn't yet know
// that we're a subscriber to the new channel. // that we're a subscriber to the new channel.
stream_create.reset_created_stream(); stream_create.reset_created_stream();
browser_history.go_to_location(hash_util.by_stream_url(sub.stream_id)); browser_history.go_to_location(hash_util.channel_url_by_user_setting(sub.stream_id));
if (stream_create.should_show_first_stream_created_modal()) { if (stream_create.should_show_first_stream_created_modal()) {
stream_create.set_first_stream_created_modal_shown(); stream_create.set_first_stream_created_modal_shown();

View File

@@ -463,7 +463,7 @@ function build_stream_sidebar_li(sub: StreamSubscription): JQuery {
const name = sub.name; const name = sub.name;
const is_muted = stream_data.is_muted(sub.stream_id); const is_muted = stream_data.is_muted(sub.stream_id);
const can_post_messages = stream_data.can_post_messages_in_stream(sub); const can_post_messages = stream_data.can_post_messages_in_stream(sub);
let url = hash_util.by_stream_url(sub.stream_id); let url = hash_util.channel_url_by_user_setting(sub.stream_id);
if ( if (
web_channel_default_view_values.list_of_topics.code === web_channel_default_view_values.list_of_topics.code ===
user_settings.web_channel_default_view user_settings.web_channel_default_view
@@ -928,7 +928,7 @@ export function set_event_handlers({
} }
if (current_narrow_stream_id === stream_id && current_topic !== undefined) { if (current_narrow_stream_id === stream_id && current_topic !== undefined) {
const channel_feed_url = hash_util.by_stream_url(stream_id); const channel_feed_url = hash_util.channel_url_by_user_setting(stream_id);
browser_history.go_to_location(channel_feed_url); browser_history.go_to_location(channel_feed_url);
return; return;
} }

View File

@@ -103,7 +103,7 @@ function build_stream_popover(opts: {elt: HTMLElement; stream_id: number}): void
return; return;
} }
const stream_hash = hash_util.by_stream_url(stream_id); const stream_hash = hash_util.channel_url_by_user_setting(stream_id);
const show_go_to_channel_feed = const show_go_to_channel_feed =
user_settings.web_channel_default_view !== user_settings.web_channel_default_view !==
web_channel_default_view_values.channel_feed.code; web_channel_default_view_values.channel_feed.code;

View File

@@ -29,7 +29,7 @@ export function set_right_panel_title(sub: StreamSubscription): void {
title_icon_color = "#dddeee"; title_icon_color = "#dddeee";
} }
const preview_url = hash_util.by_stream_url(sub.stream_id); const preview_url = hash_util.channel_url_by_user_setting(sub.stream_id);
$("#subscription_overlay .stream-info-title").html( $("#subscription_overlay .stream-info-title").html(
render_selected_stream_title({sub, title_icon_color, preview_url}), render_selected_stream_title({sub, title_icon_color, preview_url}),
); );

View File

@@ -62,7 +62,7 @@ export function get_sub_for_settings(sub: StreamSubscription): SettingsSubscript
can_remove_subscribers: stream_data.can_unsubscribe_others(sub), can_remove_subscribers: stream_data.can_unsubscribe_others(sub),
can_archive_stream: stream_data.can_archive_stream(sub), can_archive_stream: stream_data.can_archive_stream(sub),
preview_url: hash_util.by_stream_url(sub.stream_id), preview_url: hash_util.channel_url_by_user_setting(sub.stream_id),
is_old_stream: sub.stream_weekly_traffic !== null, is_old_stream: sub.stream_weekly_traffic !== null,
subscriber_count: peer_data.get_subscriber_count(sub.stream_id), subscriber_count: peer_data.get_subscriber_count(sub.stream_id),

View File

@@ -300,7 +300,7 @@ export function add_sub_to_table(sub: StreamSubscription): void {
banner_type: compose_banner.SUCCESS, banner_type: compose_banner.SUCCESS,
classname: "stream_creation_confirmation", classname: "stream_creation_confirmation",
stream_name: sub.name, stream_name: sub.name,
stream_url: hash_util.by_stream_url(sub.stream_id), stream_url: hash_util.channel_url_by_user_setting(sub.stream_id),
}; };
$("#stream_settings .stream-creation-confirmation-banner").html( $("#stream_settings .stream-creation-confirmation-banner").html(
render_stream_creation_confirmation_banner(context), render_stream_creation_confirmation_banner(context),

View File

@@ -75,7 +75,7 @@ export function get_topic_link_content(
} }
return { return {
text: `#${escape(stream_name)}`, text: `#${escape(stream_name)}`,
url: hash_util.by_stream_url(stream_id), url: hash_util.channel_url_by_user_setting(stream_id),
}; };
} }

View File

@@ -4,12 +4,18 @@ const assert = require("node:assert/strict");
const {JSDOM} = require("jsdom"); const {JSDOM} = require("jsdom");
const {zrequire} = require("./lib/namespace.cjs"); const {zrequire, mock_esm} = require("./lib/namespace.cjs");
const {run_test} = require("./lib/test.cjs"); const {run_test} = require("./lib/test.cjs");
const clipboard_handler = zrequire("clipboard_handler"); const clipboard_handler = zrequire("clipboard_handler");
const stream_data = zrequire("stream_data"); const stream_data = zrequire("stream_data");
const people = zrequire("people"); const people = zrequire("people");
const settings_config = zrequire("settings_config");
mock_esm("../src/user_settings", {
user_settings: {
web_channel_default_view: settings_config.web_channel_default_view_values.channel_feed.code,
},
});
const hamlet = { const hamlet = {
user_id: 15, user_id: 15,

View File

@@ -64,12 +64,13 @@ const composebox_typeahead = zrequire("composebox_typeahead");
const settings_config = zrequire("settings_config"); const settings_config = zrequire("settings_config");
const {set_current_user, set_realm} = zrequire("state_data"); const {set_current_user, set_realm} = zrequire("state_data");
const {initialize_user_settings} = zrequire("user_settings"); const {initialize_user_settings} = zrequire("user_settings");
const current_user = {}; const current_user = {};
set_current_user(current_user); set_current_user(current_user);
const realm = {realm_empty_topic_display_name: REALM_EMPTY_TOPIC_DISPLAY_NAME}; const realm = {realm_empty_topic_display_name: REALM_EMPTY_TOPIC_DISPLAY_NAME};
set_realm(realm); set_realm(realm);
const user_settings = {}; const user_settings = {
web_channel_default_view: settings_config.web_channel_default_view_values.channel_feed.code,
};
initialize_user_settings({user_settings}); initialize_user_settings({user_settings});
const ct = composebox_typeahead; const ct = composebox_typeahead;

View File

@@ -58,11 +58,14 @@ const pygments_data = zrequire("pygments_data");
const {set_realm} = zrequire("state_data"); const {set_realm} = zrequire("state_data");
const stream_data = zrequire("stream_data"); const stream_data = zrequire("stream_data");
const user_groups = zrequire("user_groups"); const user_groups = zrequire("user_groups");
const settings_config = zrequire("settings_config");
const {initialize_user_settings} = zrequire("user_settings"); const {initialize_user_settings} = zrequire("user_settings");
const REALM_EMPTY_TOPIC_DISPLAY_NAME = "general chat"; const REALM_EMPTY_TOPIC_DISPLAY_NAME = "general chat";
set_realm({realm_empty_topic_display_name: REALM_EMPTY_TOPIC_DISPLAY_NAME}); set_realm({realm_empty_topic_display_name: REALM_EMPTY_TOPIC_DISPLAY_NAME});
const user_settings = {}; const user_settings = {
web_channel_default_view: settings_config.web_channel_default_view_values.channel_feed.code,
};
initialize_user_settings({user_settings}); initialize_user_settings({user_settings});
const emoji_params = { const emoji_params = {

View File

@@ -98,7 +98,7 @@ mock_esm("../src/compose_closed_ui", {
update_buttons_for_non_specific_views: noop, update_buttons_for_non_specific_views: noop,
}); });
mock_esm("../src/hash_util", { mock_esm("../src/hash_util", {
by_stream_url: test_url, channel_url_by_user_setting: test_url,
by_stream_topic_url: test_url, by_stream_topic_url: test_url,
by_channel_topic_permalink: test_permalink, by_channel_topic_permalink: test_permalink,
by_conversation_and_time_url: test_url, by_conversation_and_time_url: test_url,

View File

@@ -45,6 +45,12 @@ mock_esm("../src/settings_notifications", {
mock_esm("../src/overlays", { mock_esm("../src/overlays", {
streams_open: () => true, streams_open: () => true,
}); });
const settings_config = zrequire("settings_config");
mock_esm("../src/user_settings", {
user_settings: {
web_channel_default_view: settings_config.web_channel_default_view_values.channel_feed.code,
},
});
const user_group_edit = mock_esm("../src/user_group_edit"); const user_group_edit = mock_esm("../src/user_group_edit");
const user_profile = mock_esm("../src/user_profile"); const user_profile = mock_esm("../src/user_profile");

View File

@@ -52,6 +52,7 @@ const settings_config = zrequire("settings_config");
// Start with always filtering out inactive streams. // Start with always filtering out inactive streams.
const user_settings = { const user_settings = {
demote_inactive_streams: settings_config.demote_inactive_streams_values.always.code, demote_inactive_streams: settings_config.demote_inactive_streams_values.always.code,
web_channel_default_view: settings_config.web_channel_default_view_values.channel_feed.code,
}; };
initialize_user_settings({user_settings}); initialize_user_settings({user_settings});
stream_list_sort.set_filter_out_inactives(); stream_list_sort.set_filter_out_inactives();

View File

@@ -13,7 +13,7 @@ const scroll_util = mock_esm("../src/scroll_util", {
}); });
mock_esm("../src/hash_util", { mock_esm("../src/hash_util", {
by_stream_url() {}, channel_url_by_user_setting() {},
}); });
mock_esm("../src/browser_history", { mock_esm("../src/browser_history", {

View File

@@ -2,11 +2,17 @@
const assert = require("node:assert/strict"); const assert = require("node:assert/strict");
const {zrequire} = require("./lib/namespace.cjs"); const {zrequire, mock_esm} = require("./lib/namespace.cjs");
const {run_test} = require("./lib/test.cjs"); const {run_test} = require("./lib/test.cjs");
const topic_link_util = zrequire("topic_link_util"); const topic_link_util = zrequire("topic_link_util");
const stream_data = zrequire("stream_data"); const stream_data = zrequire("stream_data");
const settings_config = zrequire("settings_config");
mock_esm("../src/user_settings", {
user_settings: {
web_channel_default_view: settings_config.web_channel_default_view_values.channel_feed.code,
},
});
const sweden_stream = { const sweden_stream = {
name: "Sweden", name: "Sweden",