left_sidebar: Change channel sections to togglable sections.

This commit is contained in:
Evy Kassirer
2025-06-20 21:30:50 -07:00
committed by Tim Abbott
parent dc013b6a10
commit 27092d5543
9 changed files with 373 additions and 396 deletions

View File

@@ -21,7 +21,7 @@ let unread_unmuted_count;
let stream_has_any_unread_mentions;
const topic_list = mock_esm("../src/topic_list");
const scroll_util = mock_esm("../src/scroll_util", {
mock_esm("../src/scroll_util", {
scroll_element_into_container() {},
get_scroll_element: ($element) => $element,
});
@@ -101,11 +101,6 @@ const social = {
can_send_message_group: everyone_group.id,
};
// flag to check if subheader is rendered
let pinned_subheader_flag = false;
let active_subheader_flag = false;
let inactive_subheader_flag = false;
function create_devel_sidebar_row({mock_template}) {
const $devel_count = $.create("devel-count");
const $subscription_block = $.create("devel-block");
@@ -152,22 +147,6 @@ function create_social_sidebar_row({mock_template}) {
assert.equal($social_unread_mention_info.text(), "@");
}
function create_stream_subheader({mock_template}) {
mock_template("streams_subheader.hbs", false, (data) => {
if (data.subheader_name === "translated: Pinned") {
pinned_subheader_flag = true;
return "<pinned-subheader-stub>";
} else if (data.subheader_name === "translated: Active") {
active_subheader_flag = true;
return "<active-subheader-stub>";
}
assert.ok(data.subheader_name === "translated: Inactive");
inactive_subheader_flag = true;
return "<inactive-subheader-stub>";
});
}
function test_ui(label, f) {
run_test(label, (helpers) => {
stream_data.clear_subscriptions();
@@ -176,48 +155,46 @@ function test_ui(label, f) {
});
}
test_ui("create_sidebar_row", ({override, mock_template}) => {
test_ui("create_sidebar_row", ({override, override_rewire, mock_template}) => {
// Make a couple calls to create_sidebar_row() and make sure they
// generate the right markup as well as play nice with get_stream_li().
override(user_settings, "demote_inactive_streams", 1);
const appended_sections = [];
override_rewire(stream_list, "stream_list_section_container_html", (section) => {
appended_sections.push(section.id);
return `<stub-section-${section.id}>`;
});
const pinned_streams = [];
$("#stream-list-pinned-streams").append = (stream) => {
pinned_streams.push(stream);
};
const normal_streams = [];
$("#stream-list-normal-streams").append = (stream) => {
normal_streams.push(stream);
};
stream_data.add_sub(devel);
stream_data.add_sub(social);
create_devel_sidebar_row({mock_template});
create_social_sidebar_row({mock_template});
create_stream_subheader({mock_template});
topic_list.get_stream_li = noop;
const $pinned_subheader = $("<pinned-subheader-stub>");
const $active_subheader = $("<active-subheader-stub>");
const $devel_sidebar = $("<devel-sidebar-row-stub>");
const $social_sidebar = $("<social-sidebar-row-stub>");
let appended_elems;
$("#stream_filters").append = (elems) => {
appended_elems = elems;
};
let topics_closed;
topic_list.close = () => {
topics_closed = true;
};
stream_list.build_stream_list();
assert.ok(topics_closed);
const expected_elems = [
$pinned_subheader, // separator
$devel_sidebar, // pinned
$active_subheader, // separator
$social_sidebar, // not pinned
];
assert.deepEqual(appended_sections, ["pinned-streams", "normal-streams", "dormant-streams"]);
assert.deepEqual(appended_elems, expected_elems);
assert.ok(pinned_subheader_flag);
assert.ok(active_subheader_flag);
assert.deepEqual(pinned_streams, [$devel_sidebar]);
assert.deepEqual(normal_streams, [$social_sidebar]);
const $social_li = $("<social-sidebar-row-stub>");
const stream_id = social.stream_id;
@@ -267,8 +244,6 @@ test_ui("pinned_streams_never_inactive", ({mock_template}) => {
create_devel_sidebar_row({mock_template});
create_social_sidebar_row({mock_template});
create_stream_subheader({mock_template});
// non-pinned streams can be made inactive
const $social_sidebar = $("<social-sidebar-row-stub>");
let stream_id = social.stream_id;
@@ -397,15 +372,6 @@ function elem($obj) {
test_ui("zoom_in_and_zoom_out", ({mock_template}) => {
topic_list.setup_topic_search_typeahead = noop;
const $splitter = $.create("<active-subheader-stub>");
$splitter.show();
assert.ok($splitter.visible());
$.create(".streams_subheader", {
children: [elem($splitter)],
});
const $stream_li1 = $.create("stream1 stub");
const $stream_li2 = $.create("stream2 stub");
@@ -439,7 +405,6 @@ test_ui("zoom_in_and_zoom_out", ({mock_template}) => {
});
stream_list.zoom_in_topics({stream_id: 42});
assert.ok(!$splitter.visible());
assert.ok(!$stream_li1.hasClass("hide"));
assert.ok($stream_li2.hasClass("hide"));
assert.ok($("#streams_list").hasClass("zoom-in"));
@@ -456,22 +421,20 @@ test_ui("zoom_in_and_zoom_out", ({mock_template}) => {
};
stream_list.zoom_out_topics({$stream_li: $stream_li1});
assert.ok($splitter.visible());
assert.ok(!$stream_li1.hasClass("hide"));
assert.ok(!$stream_li2.hasClass("hide"));
assert.ok($("#streams_list").hasClass("zoom-out"));
assert.ok(!filter_topics_appended);
});
test_ui("narrowing", ({mock_template}) => {
create_stream_subheader({mock_template});
test_ui("narrowing", ({override_rewire}) => {
initialize_stream_data();
topic_list.close = noop;
topic_list.rebuild_left_sidebar = noop;
topic_list.active_stream_id = noop;
topic_list.get_stream_li = noop;
$("#streams_header").outerHeight = () => 0;
override_rewire(stream_list, "scroll_stream_into_view", noop);
assert.ok(!$("<devel-sidebar-row-stub>").hasClass("active-filter"));
@@ -529,44 +492,45 @@ test_ui("focus_user_filter", () => {
click_handler(e);
});
test_ui("sort_streams", ({mock_template}) => {
create_stream_subheader({mock_template});
// Set subheader flag to false
pinned_subheader_flag = false;
active_subheader_flag = false;
inactive_subheader_flag = false;
test_ui("sort_streams", ({override_rewire}) => {
// Get coverage on early-exit.
stream_list.build_stream_list();
initialize_stream_data();
let appended_elems;
$("#stream_filters").append = (elems) => {
appended_elems = elems;
const appended_sections = [];
override_rewire(stream_list, "stream_list_section_container_html", (section) => {
appended_sections.push(section.id);
return `<stub-section-${section.id}>`;
});
const pinned_streams = [];
$("#stream-list-pinned-streams").append = (stream) => {
pinned_streams.push(stream);
};
const normal_streams = [];
$("#stream-list-normal-streams").append = (stream) => {
normal_streams.push(stream);
};
const inactive_streams = [];
$("#stream-list-dormant-streams").append = (stream) => {
inactive_streams.push(stream);
};
stream_list.build_stream_list(true);
const $pinned_subheader = $("<pinned-subheader-stub>");
const $active_subheader = $("<active-subheader-stub>");
const $inactive_subheader = $("<inactive-subheader-stub>");
const expected_elems = [
$pinned_subheader,
assert.deepEqual(appended_sections, ["pinned-streams", "normal-streams", "dormant-streams"]);
assert.deepEqual(pinned_streams, [
$("<devel-sidebar-row-stub>"),
$("<Rome-sidebar-row-stub>"),
$("<test-sidebar-row-stub>"),
$active_subheader,
]);
assert.deepEqual(normal_streams, [
$("<announce-sidebar-row-stub>"),
$("<Denmark-sidebar-row-stub>"),
$inactive_subheader,
$("<cars-sidebar-row-stub>"),
];
assert.deepEqual(appended_elems, expected_elems);
assert.ok(pinned_subheader_flag);
assert.ok(active_subheader_flag);
assert.ok(inactive_subheader_flag);
]);
assert.deepEqual(inactive_streams, [$("<cars-sidebar-row-stub>")]);
const streams = stream_list_sort.get_stream_ids();
@@ -589,13 +553,7 @@ test_ui("sort_streams", ({mock_template}) => {
assert.ok(!stream_list.stream_sidebar.has_row_for(stream_id));
});
test_ui("separators_only_pinned_and_dormant", ({mock_template}) => {
// Test only pinned and dormant streams
create_stream_subheader({mock_template});
pinned_subheader_flag = false;
inactive_subheader_flag = false;
test_ui("separators_only_pinned_and_dormant", ({override_rewire}) => {
// Get coverage on early-exit.
stream_list.build_stream_list();
@@ -630,73 +588,31 @@ test_ui("separators_only_pinned_and_dormant", ({mock_template}) => {
};
add_row(DenmarkSub);
let appended_elems;
$("#stream_filters").append = (elems) => {
appended_elems = elems;
const appended_sections = [];
override_rewire(stream_list, "stream_list_section_container_html", (section) => {
appended_sections.push(section.id);
return `<stub-section-${section.id}>`;
});
const pinned_streams = [];
$("#stream-list-pinned-streams").append = (stream) => {
pinned_streams.push(stream);
};
const inactive_streams = [];
$("#stream-list-dormant-streams").append = (stream) => {
inactive_streams.push(stream);
};
stream_list.build_stream_list();
const $pinned_subheader = $("<pinned-subheader-stub>");
const $inactive_subheader = $("<inactive-subheader-stub>");
const expected_elems = [
$pinned_subheader, // pinned
$("<devel-sidebar-row-stub>"),
$("<Rome-sidebar-row-stub>"),
$inactive_subheader, // dormant
$("<Denmark-sidebar-row-stub>"),
];
assert.deepEqual(appended_sections, ["pinned-streams", "normal-streams", "dormant-streams"]);
assert.deepEqual(appended_elems, expected_elems);
assert.ok(pinned_subheader_flag);
assert.ok(inactive_subheader_flag);
});
test_ui("separators_only_pinned", () => {
// Test only pinned streams
// Get coverage on early-exit.
stream_list.build_stream_list();
// pinned streams
const develSub = {
name: "devel",
stream_id: 1000,
color: "blue",
pin_to_top: true,
subscribed: true,
};
add_row(develSub);
const RomeSub = {
name: "Rome",
stream_id: 2000,
color: "blue",
pin_to_top: true,
subscribed: true,
};
add_row(RomeSub);
let appended_elems;
$("#stream_filters").append = (elems) => {
appended_elems = elems;
};
stream_list.build_stream_list();
const expected_elems = [
// no section sub-header since there is only one section
$("<devel-sidebar-row-stub>"),
$("<Rome-sidebar-row-stub>"),
// no separator at the end as no stream follows
];
assert.deepEqual(appended_elems, expected_elems);
assert.deepEqual(pinned_streams, [$("<devel-sidebar-row-stub>"), $("<Rome-sidebar-row-stub>")]);
assert.deepEqual(inactive_streams, [$("<Denmark-sidebar-row-stub>")]);
});
test_ui("rename_stream", ({mock_template, override}) => {
override(user_settings, "web_stream_unreads_count_display_policy", 3);
override(current_user, "user_id", me.user_id);
create_stream_subheader({mock_template});
initialize_stream_data();
const sub = stream_data.get_sub_by_name("devel");
@@ -737,7 +653,7 @@ test_ui("rename_stream", ({mock_template, override}) => {
develSub.name = "devel"; // Resets
});
test_ui("refresh_pin", ({override, override_rewire, mock_template}) => {
test_ui("refresh_pin", ({override_rewire, mock_template}) => {
initialize_stream_data();
const sub = {
@@ -762,10 +678,9 @@ test_ui("refresh_pin", ({override, override_rewire, mock_template}) => {
override_rewire(stream_list, "update_count_in_dom", noop);
$("#stream_filters").append = noop;
$("#streams_header").outerHeight = () => 0;
let scrolled;
override(scroll_util, "scroll_element_into_container", ($li) => {
override_rewire(stream_list, "scroll_stream_into_view", ($li) => {
if ($li === $li_stub) {
scrolled = true;
}

View File

@@ -100,11 +100,26 @@ function test(label, f) {
test("no_subscribed_streams", () => {
const sorted = sort_groups("");
assert.deepEqual(sorted, {
dormant_streams: [],
muted_active_streams: [],
muted_pinned_streams: [],
normal_streams: [],
pinned_streams: [],
sections: [
{
id: "pinned-streams",
muted_streams: [],
section_title: "translated: PINNED CHANNELS",
streams: [],
},
{
id: "normal-streams",
muted_streams: [],
section_title: "translated: ACTIVE CHANNELS",
streams: [],
},
{
id: "dormant-streams",
muted_streams: [],
section_title: "translated: INACTIVE CHANNELS",
streams: [],
},
],
same_as_before: sorted.same_as_before,
});
assert.equal(stream_list_sort.first_stream_id(), undefined);
@@ -122,16 +137,22 @@ test("basics", () => {
stream_data.add_sub(archived);
// Test sorting into categories/alphabetized
let sorted = sort_groups("");
assert.deepEqual(sorted.pinned_streams, [scalene.stream_id]);
assert.deepEqual(sorted.normal_streams, [
let sorted_sections = sort_groups("").sections;
const pinned = sorted_sections[0];
assert.deepEqual(pinned.id, "pinned-streams");
assert.deepEqual(pinned.streams, [scalene.stream_id]);
assert.deepEqual(pinned.muted_streams, [muted_pinned.stream_id]);
const normal = sorted_sections[1];
assert.deepEqual(normal.id, "normal-streams");
assert.deepEqual(normal.streams, [
clarinet.stream_id,
fast_tortoise.stream_id,
stream_hyphen_underscore_slash_colon.stream_id,
]);
assert.deepEqual(sorted.muted_pinned_streams, [muted_pinned.stream_id]);
assert.deepEqual(sorted.muted_active_streams, [muted_active.stream_id]);
assert.deepEqual(sorted.dormant_streams, [pneumonia.stream_id]);
assert.deepEqual(normal.muted_streams, [muted_active.stream_id]);
const dormant = sorted_sections[2];
assert.deepEqual(dormant.id, "dormant-streams");
assert.deepEqual(dormant.streams, [pneumonia.stream_id]);
// Test cursor helpers.
assert.equal(stream_list_sort.first_stream_id(), scalene.stream_id);
@@ -156,53 +177,70 @@ test("basics", () => {
assert.equal(stream_list_sort.next_stream_id(pneumonia.stream_id), undefined);
// Test filtering
sorted = sort_groups("s");
assert.deepEqual(sorted.pinned_streams, [scalene.stream_id]);
assert.deepEqual(sorted.normal_streams, [stream_hyphen_underscore_slash_colon.stream_id]);
assert.deepEqual(sorted.dormant_streams, []);
sorted_sections = sort_groups("s").sections;
assert.deepEqual(sorted_sections.length, 3);
assert.deepEqual(sorted_sections[0].id, "pinned-streams");
assert.deepEqual(sorted_sections[0].streams, [scalene.stream_id]);
assert.deepEqual(sorted_sections[1].id, "normal-streams");
assert.deepEqual(sorted_sections[1].streams, [stream_hyphen_underscore_slash_colon.stream_id]);
assert.deepEqual(sorted_sections[2].streams, []);
assert.equal(stream_list_sort.prev_stream_id(clarinet.stream_id), undefined);
assert.equal(stream_list_sort.next_stream_id(clarinet.stream_id), undefined);
// Test searching entire word, case-insensitive
sorted = sort_groups("PnEuMoNiA");
assert.deepEqual(sorted.pinned_streams, []);
assert.deepEqual(sorted.normal_streams, []);
assert.deepEqual(sorted.dormant_streams, [pneumonia.stream_id]);
sorted_sections = sort_groups("PnEuMoNiA").sections;
assert.deepEqual(sorted_sections.length, 3);
assert.deepEqual(sorted_sections[0].streams, []);
assert.deepEqual(sorted_sections[1].streams, []);
assert.deepEqual(sorted_sections[2].id, "dormant-streams");
assert.deepEqual(sorted_sections[2].streams, [pneumonia.stream_id]);
// Test searching part of word
sorted = sort_groups("tortoise");
assert.deepEqual(sorted.pinned_streams, []);
assert.deepEqual(sorted.normal_streams, [fast_tortoise.stream_id]);
assert.deepEqual(sorted.dormant_streams, []);
sorted_sections = sort_groups("tortoise").sections;
assert.deepEqual(sorted_sections.length, 3);
assert.deepEqual(sorted_sections[0].streams, []);
assert.deepEqual(sorted_sections[1].id, "normal-streams");
assert.deepEqual(sorted_sections[1].streams, [fast_tortoise.stream_id]);
assert.deepEqual(sorted_sections[2].streams, []);
// Test searching stream with spaces
sorted = sort_groups("fast t");
assert.deepEqual(sorted.pinned_streams, []);
assert.deepEqual(sorted.normal_streams, [fast_tortoise.stream_id]);
assert.deepEqual(sorted.dormant_streams, []);
sorted_sections = sort_groups("fast t").sections;
assert.deepEqual(sorted_sections.length, 3);
assert.deepEqual(sorted_sections[0].streams, []);
assert.deepEqual(sorted_sections[1].id, "normal-streams");
assert.deepEqual(sorted_sections[1].streams, [fast_tortoise.stream_id]);
assert.deepEqual(sorted_sections[2].streams, []);
// Test searching part of stream name with non space word separators
sorted = sort_groups("hyphen");
assert.deepEqual(sorted.pinned_streams, []);
assert.deepEqual(sorted.normal_streams, [stream_hyphen_underscore_slash_colon.stream_id]);
assert.deepEqual(sorted.dormant_streams, []);
sorted_sections = sort_groups("hyphen").sections;
assert.deepEqual(sorted_sections.length, 3);
assert.deepEqual(sorted_sections[0].streams, []);
assert.deepEqual(sorted_sections[1].id, "normal-streams");
assert.deepEqual(sorted_sections[1].streams, [stream_hyphen_underscore_slash_colon.stream_id]);
assert.deepEqual(sorted_sections[2].streams, []);
sorted = sort_groups("hyphen_underscore");
assert.deepEqual(sorted.pinned_streams, []);
assert.deepEqual(sorted.normal_streams, [stream_hyphen_underscore_slash_colon.stream_id]);
assert.deepEqual(sorted.dormant_streams, []);
sorted_sections = sort_groups("hyphen_underscore").sections;
assert.deepEqual(sorted_sections.length, 3);
assert.deepEqual(sorted_sections[0].streams, []);
assert.deepEqual(sorted_sections[1].id, "normal-streams");
assert.deepEqual(sorted_sections[1].streams, [stream_hyphen_underscore_slash_colon.stream_id]);
assert.deepEqual(sorted_sections[2].streams, []);
sorted = sort_groups("colon");
assert.deepEqual(sorted.pinned_streams, []);
assert.deepEqual(sorted.normal_streams, [stream_hyphen_underscore_slash_colon.stream_id]);
assert.deepEqual(sorted.dormant_streams, []);
sorted_sections = sort_groups("colon").sections;
assert.deepEqual(sorted_sections.length, 3);
assert.deepEqual(sorted_sections[0].streams, []);
assert.deepEqual(sorted_sections[1].id, "normal-streams");
assert.deepEqual(sorted_sections[1].streams, [stream_hyphen_underscore_slash_colon.stream_id]);
assert.deepEqual(sorted_sections[2].streams, []);
sorted = sort_groups("underscore");
assert.deepEqual(sorted.pinned_streams, []);
assert.deepEqual(sorted.normal_streams, [stream_hyphen_underscore_slash_colon.stream_id]);
assert.deepEqual(sorted.dormant_streams, []);
sorted_sections = sort_groups("underscore").sections;
assert.deepEqual(sorted_sections.length, 3);
assert.deepEqual(sorted_sections[0].streams, []);
assert.deepEqual(sorted_sections[1].id, "normal-streams");
assert.deepEqual(sorted_sections[1].streams, [stream_hyphen_underscore_slash_colon.stream_id]);
assert.deepEqual(sorted_sections[2].streams, []);
});
test("filter inactives", ({override}) => {