mirror of
https://github.com/zulip/zulip.git
synced 2025-10-26 09:34:02 +00:00
stream_sidebar: Implement stream navigation behavior.
Clicking on the name of a stream in the left sidebar now navigates to the top topic in the left sidebar view of that stream, rather than an interleaved view. Added an "interleaved" button to the stream popover row in the left sidebar that appears only when the user hovers over it. Fixes #26937. Co-authored-by: Aman Agrawal <amanagr@zulip.com>
This commit is contained in:
@@ -33,6 +33,17 @@ async function expect_home(page: Page): Promise<void> {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function expect_verona_stream_top_topic(page: Page): Promise<void> {
|
||||||
|
const message_list_id = await common.get_current_msg_list_id(page, true);
|
||||||
|
await page.waitForSelector(`.message-list[data-message-list-id='${message_list_id}']`, {
|
||||||
|
visible: true,
|
||||||
|
});
|
||||||
|
await common.check_messages_sent(page, message_list_id, [
|
||||||
|
["Verona > test", ["verona test a", "verona test b", "verona test d"]],
|
||||||
|
]);
|
||||||
|
assert.strictEqual(await page.title(), "#Verona > test - Zulip Dev - Zulip");
|
||||||
|
}
|
||||||
|
|
||||||
async function expect_verona_stream(page: Page): Promise<void> {
|
async function expect_verona_stream(page: Page): Promise<void> {
|
||||||
const message_list_id = await common.get_current_msg_list_id(page, true);
|
const message_list_id = await common.get_current_msg_list_id(page, true);
|
||||||
await page.waitForSelector(`.message-list[data-message-list-id='${message_list_id}']`, {
|
await page.waitForSelector(`.message-list[data-message-list-id='${message_list_id}']`, {
|
||||||
@@ -313,8 +324,8 @@ async function expect_all_direct_messages(page: Page): Promise<void> {
|
|||||||
async function test_narrow_by_clicking_the_left_sidebar(page: Page): Promise<void> {
|
async function test_narrow_by_clicking_the_left_sidebar(page: Page): Promise<void> {
|
||||||
console.log("Narrowing with left sidebar");
|
console.log("Narrowing with left sidebar");
|
||||||
|
|
||||||
await page.click((await get_stream_li(page, "Verona")) + " a");
|
await page.click((await get_stream_li(page, "Verona")) + " .stream-name");
|
||||||
await expect_verona_stream(page);
|
await expect_verona_stream_top_topic(page);
|
||||||
|
|
||||||
await page.click("#left-sidebar-navigation-list .top_left_all_messages a");
|
await page.click("#left-sidebar-navigation-list .top_left_all_messages a");
|
||||||
await expect_home(page);
|
await expect_home(page);
|
||||||
@@ -424,7 +435,7 @@ async function test_stream_search_filters_stream_list(page: Page): Promise<void>
|
|||||||
await page.waitForSelector(await get_stream_li(page, "Denmark"), {hidden: true});
|
await page.waitForSelector(await get_stream_li(page, "Denmark"), {hidden: true});
|
||||||
await page.waitForSelector(await get_stream_li(page, "Venice"), {hidden: true});
|
await page.waitForSelector(await get_stream_li(page, "Venice"), {hidden: true});
|
||||||
await page.click(await get_stream_li(page, "Verona"));
|
await page.click(await get_stream_li(page, "Verona"));
|
||||||
await expect_verona_stream(page);
|
await expect_verona_stream_top_topic(page);
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
await common.get_text_from_selector(page, ".stream-list-filter"),
|
await common.get_text_from_selector(page, ".stream-list-filter"),
|
||||||
"",
|
"",
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import type {Page} from "puppeteer";
|
|||||||
|
|
||||||
import * as common from "./lib/common";
|
import * as common from "./lib/common";
|
||||||
|
|
||||||
async function navigate_using_left_sidebar(page: Page, click_target: string): Promise<void> {
|
async function navigate_using_left_sidebar(page: Page, stream_name: string): Promise<void> {
|
||||||
console.log("Visiting #" + click_target);
|
console.log("Visiting #" + stream_name);
|
||||||
await page.click(`#left-sidebar a[href='#${CSS.escape(click_target)}']`);
|
await page.click(`.stream-name[title="${stream_name}"]`);
|
||||||
await page.waitForSelector(`#message_feed_container`, {visible: true});
|
await page.waitForSelector(`#message_feed_container`, {visible: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,10 +92,7 @@ async function navigation_tests(page: Page): Promise<void> {
|
|||||||
|
|
||||||
await navigate_to_settings(page);
|
await navigate_to_settings(page);
|
||||||
|
|
||||||
const verona_id = await page.evaluate(() => zulip_test.get_stream_id("Verona"));
|
await navigate_using_left_sidebar(page, "Verona");
|
||||||
const verona_narrow = `narrow/stream/${verona_id}-Verona`;
|
|
||||||
|
|
||||||
await navigate_using_left_sidebar(page, verona_narrow);
|
|
||||||
|
|
||||||
await page.click("#left-sidebar-navigation-list .home-link");
|
await page.click("#left-sidebar-navigation-list .home-link");
|
||||||
await page.waitForSelector("#message_feed_container", {visible: true});
|
await page.waitForSelector("#message_feed_container", {visible: true});
|
||||||
@@ -108,7 +105,7 @@ async function navigation_tests(page: Page): Promise<void> {
|
|||||||
await navigate_to_settings(page);
|
await navigate_to_settings(page);
|
||||||
await navigate_to_private_messages(page);
|
await navigate_to_private_messages(page);
|
||||||
await navigate_to_subscriptions(page);
|
await navigate_to_subscriptions(page);
|
||||||
await navigate_using_left_sidebar(page, verona_narrow);
|
await navigate_using_left_sidebar(page, "Verona");
|
||||||
|
|
||||||
await test_reload_hash(page);
|
await test_reload_hash(page);
|
||||||
|
|
||||||
|
|||||||
@@ -20,16 +20,21 @@ import * as pm_list from "./pm_list";
|
|||||||
import * as popovers from "./popovers";
|
import * as popovers from "./popovers";
|
||||||
import * as resize from "./resize";
|
import * as resize from "./resize";
|
||||||
import * as scroll_util from "./scroll_util";
|
import * as scroll_util from "./scroll_util";
|
||||||
|
import {web_channel_default_view_values} from "./settings_config";
|
||||||
import * as settings_data from "./settings_data";
|
import * as settings_data from "./settings_data";
|
||||||
import * as sidebar_ui from "./sidebar_ui";
|
import * as sidebar_ui from "./sidebar_ui";
|
||||||
import * as stream_data from "./stream_data";
|
import * as stream_data from "./stream_data";
|
||||||
import * as stream_list_sort from "./stream_list_sort";
|
import * as stream_list_sort from "./stream_list_sort";
|
||||||
|
import * as stream_topic_history from "./stream_topic_history";
|
||||||
|
import * as stream_topic_history_util from "./stream_topic_history_util";
|
||||||
import * as sub_store from "./sub_store";
|
import * as sub_store from "./sub_store";
|
||||||
import type {StreamSubscription} from "./sub_store";
|
import type {StreamSubscription} from "./sub_store";
|
||||||
import * as topic_list from "./topic_list";
|
import * as topic_list from "./topic_list";
|
||||||
import * as ui_util from "./ui_util";
|
import * as ui_util from "./ui_util";
|
||||||
import * as unread from "./unread";
|
import * as unread from "./unread";
|
||||||
import type {FullUnreadCountsData, StreamCountInfo} from "./unread";
|
import type {FullUnreadCountsData, StreamCountInfo} from "./unread";
|
||||||
|
import {user_settings} from "./user_settings";
|
||||||
|
import * as user_topics from "./user_topics";
|
||||||
|
|
||||||
let pending_stream_list_rerender = false;
|
let pending_stream_list_rerender = false;
|
||||||
let zoomed_in = false;
|
let zoomed_in = false;
|
||||||
@@ -837,17 +842,63 @@ export function set_event_handlers({
|
|||||||
}: {
|
}: {
|
||||||
on_stream_click: (stream_id: number, trigger: string) => void;
|
on_stream_click: (stream_id: number, trigger: string) => void;
|
||||||
}): void {
|
}): void {
|
||||||
$("#stream_filters").on("click", "li .subscription_block", (e) => {
|
$("#stream_filters").on("click", "li .subscription_block .stream-name", (e) => {
|
||||||
if (e.metaKey || e.ctrlKey || e.shiftKey) {
|
if (e.metaKey || e.ctrlKey || e.shiftKey) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const stream_id = stream_id_for_elt($(e.target).parents("li"));
|
|
||||||
on_stream_click(stream_id, "sidebar");
|
|
||||||
|
|
||||||
clear_and_hide_search();
|
clear_and_hide_search();
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
|
const stream_id = stream_id_for_elt($(e.target).parents("li"));
|
||||||
|
|
||||||
|
if (
|
||||||
|
user_settings.web_channel_default_view ===
|
||||||
|
web_channel_default_view_values.channel_feed.code
|
||||||
|
) {
|
||||||
|
on_stream_click(stream_id, "sidebar");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let topics = stream_topic_history.get_recent_topic_names(stream_id);
|
||||||
|
|
||||||
|
const navigate_to_stream = (): void => {
|
||||||
|
let destination_url;
|
||||||
|
|
||||||
|
const top_unmuted_topic = topics.find(
|
||||||
|
(topic) => !user_topics.is_topic_muted(stream_id, topic),
|
||||||
|
);
|
||||||
|
const muted_topics = topics.find((topic) =>
|
||||||
|
user_topics.is_topic_muted(stream_id, topic),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (top_unmuted_topic) {
|
||||||
|
destination_url = hash_util.by_stream_topic_url(stream_id, top_unmuted_topic);
|
||||||
|
browser_history.go_to_location(destination_url);
|
||||||
|
} else if (muted_topics) {
|
||||||
|
destination_url = hash_util.by_stream_topic_url(stream_id, muted_topics);
|
||||||
|
browser_history.go_to_location(destination_url);
|
||||||
|
} else {
|
||||||
|
on_stream_click(stream_id, "sidebar");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (topics.length === 0) {
|
||||||
|
stream_topic_history_util.get_server_history(stream_id, () => {
|
||||||
|
topics = stream_topic_history.get_recent_topic_names(stream_id);
|
||||||
|
if (topics.length === 0) {
|
||||||
|
on_stream_click(stream_id, "sidebar");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
navigate_to_stream();
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
navigate_to_stream();
|
||||||
|
return;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#clear_search_stream_button").on("click", clear_search);
|
$("#clear_search_stream_button").on("click", clear_search);
|
||||||
|
|||||||
@@ -15,8 +15,10 @@ import * as hash_util from "./hash_util";
|
|||||||
import {$t, $t_html} from "./i18n";
|
import {$t, $t_html} from "./i18n";
|
||||||
import * as message_edit from "./message_edit";
|
import * as message_edit from "./message_edit";
|
||||||
import * as message_lists from "./message_lists";
|
import * as message_lists from "./message_lists";
|
||||||
|
import * as message_view from "./message_view";
|
||||||
import * as popover_menus from "./popover_menus";
|
import * as popover_menus from "./popover_menus";
|
||||||
import {left_sidebar_tippy_options} from "./popover_menus";
|
import {left_sidebar_tippy_options} from "./popover_menus";
|
||||||
|
import {web_channel_default_view_values} from "./settings_config";
|
||||||
import * as settings_data from "./settings_data";
|
import * as settings_data from "./settings_data";
|
||||||
import * as stream_color from "./stream_color";
|
import * as stream_color from "./stream_color";
|
||||||
import * as stream_data from "./stream_data";
|
import * as stream_data from "./stream_data";
|
||||||
@@ -27,6 +29,7 @@ import * as sub_store from "./sub_store";
|
|||||||
import * as ui_report from "./ui_report";
|
import * as ui_report from "./ui_report";
|
||||||
import * as ui_util from "./ui_util";
|
import * as ui_util from "./ui_util";
|
||||||
import * as unread_ops from "./unread_ops";
|
import * as unread_ops from "./unread_ops";
|
||||||
|
import {user_settings} from "./user_settings";
|
||||||
import * as util from "./util";
|
import * as util from "./util";
|
||||||
// In this module, we manage stream popovers
|
// In this module, we manage stream popovers
|
||||||
// that pop up from the left sidebar.
|
// that pop up from the left sidebar.
|
||||||
@@ -96,8 +99,12 @@ function build_stream_popover(opts) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const show_go_to_channel_feed =
|
||||||
|
user_settings.web_channel_default_view !==
|
||||||
|
web_channel_default_view_values.channel_feed.code;
|
||||||
const content = render_left_sidebar_stream_actions_popover({
|
const content = render_left_sidebar_stream_actions_popover({
|
||||||
stream: sub_store.get(stream_id),
|
stream: sub_store.get(stream_id),
|
||||||
|
show_go_to_channel_feed,
|
||||||
});
|
});
|
||||||
|
|
||||||
popover_menus.toggle_popover_menu(elt, {
|
popover_menus.toggle_popover_menu(elt, {
|
||||||
@@ -116,6 +123,23 @@ function build_stream_popover(opts) {
|
|||||||
const $popper = $(instance.popper);
|
const $popper = $(instance.popper);
|
||||||
ui_util.show_left_sidebar_menu_icon(elt);
|
ui_util.show_left_sidebar_menu_icon(elt);
|
||||||
|
|
||||||
|
// Go to channel feed instead of first topic.
|
||||||
|
$popper.on("click", ".stream-popover-go-to-channel-feed", (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
const sub = stream_popover_sub(e);
|
||||||
|
hide_stream_popover();
|
||||||
|
message_view.show(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
operator: "stream",
|
||||||
|
operand: sub.name,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
{trigger: "stream-popover"},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
// Stream settings
|
// Stream settings
|
||||||
$popper.on("click", ".open_stream_settings", (e) => {
|
$popper.on("click", ".open_stream_settings", (e) => {
|
||||||
const sub = stream_popover_sub(e);
|
const sub = stream_popover_sub(e);
|
||||||
|
|||||||
@@ -9,6 +9,14 @@
|
|||||||
<span class="popover-stream-name">{{stream.name}}</span>
|
<span class="popover-stream-name">{{stream.name}}</span>
|
||||||
</li>
|
</li>
|
||||||
<li role="separator" class="popover-menu-separator"></li>
|
<li role="separator" class="popover-menu-separator"></li>
|
||||||
|
{{#if show_go_to_channel_feed}}
|
||||||
|
<li role="none" class="link-item popover-menu-inner-list-item">
|
||||||
|
<a role="menuitem" class="stream-popover-go-to-channel-feed popover-menu-link" tabindex="0">
|
||||||
|
<i class="popover-menu-icon zulip-icon zulip-icon-all-messages" aria-hidden="true"></i>
|
||||||
|
<span class="popover-menu-label">{{t "Go to channel feed" }}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{/if}}
|
||||||
<li role="none" class="link-item popover-menu-inner-list-item">
|
<li role="none" class="link-item popover-menu-inner-list-item">
|
||||||
<a role="menuitem" class="open_stream_settings popover-menu-link" tabindex="0">
|
<a role="menuitem" class="open_stream_settings popover-menu-link" tabindex="0">
|
||||||
<i class="popover-menu-icon zulip-icon zulip-icon-gear" aria-hidden="true"></i>
|
<i class="popover-menu-icon zulip-icon zulip-icon-gear" aria-hidden="true"></i>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
{{> stream_privacy }}
|
{{> stream_privacy }}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<a href="{{url}}" title="{{name}}" class="stream-name">{{name}}</a>
|
<span title="{{name}}" class="stream-name">{{name}}</span>
|
||||||
|
|
||||||
<div class="stream-markers-and-controls">
|
<div class="stream-markers-and-controls">
|
||||||
<span class="unread_mention_info"></span>
|
<span class="unread_mention_info"></span>
|
||||||
|
|||||||
Reference in New Issue
Block a user