dropdown: Add ability to update items in dropdown widget.

This is needed for the compose stream dropdown widget,
which is also updated here. Now when a user is subscribed
or unsubscribed from a stream, or a stream is renamed, or
or a stream is deleted, the dropdown widget updates
accordingly. This fixes a regression of this functionality
that happened during the switch to the dropdown.
This commit is contained in:
evykassirer 2023-02-09 12:45:47 -08:00 committed by Tim Abbott
parent 19a47a71d8
commit 584d3c66a3
9 changed files with 71 additions and 13 deletions

View File

@ -5,6 +5,7 @@ import {insert, replace, set, wrapSelection} from "text-field-edit";
import * as common from "./common"; import * as common from "./common";
import * as compose from "./compose"; import * as compose from "./compose";
import * as compose_actions from "./compose_actions"; import * as compose_actions from "./compose_actions";
import * as compose_state from "./compose_state";
import {DropdownListWidget} from "./dropdown_list_widget"; import {DropdownListWidget} from "./dropdown_list_widget";
import {$t} from "./i18n"; import {$t} from "./i18n";
import * as loading from "./loading"; import * as loading from "./loading";
@ -558,3 +559,30 @@ export function initialize_compose_stream_dropdown() {
e.stopPropagation(); e.stopPropagation();
}); });
} }
export function update_stream_dropdown_options() {
const streams_list = stream_data
.subscribed_subs()
.filter((stream) => stream_data.can_post_messages_in_stream(stream))
.map((stream) => ({
name: stream.name,
value: stream.name,
}))
.sort((a, b) => {
if (a.name.toLowerCase() < b.name.toLowerCase()) {
return -1;
}
if (a.name.toLowerCase() > b.name.toLowerCase()) {
return 1;
}
return 0;
});
compose_stream_widget.replace_data(streams_list);
}
export function possibly_update_dropdown_selection(old_stream_name, new_stream_name) {
const selected_stream = compose_state.stream_name();
if (selected_stream === old_stream_name) {
compose_state.set_stream_name(new_stream_name);
}
}

View File

@ -11,6 +11,7 @@ import * as compose from "./compose";
import * as compose_actions from "./compose_actions"; import * as compose_actions from "./compose_actions";
import * as compose_fade from "./compose_fade"; import * as compose_fade from "./compose_fade";
import * as compose_pm_pill from "./compose_pm_pill"; import * as compose_pm_pill from "./compose_pm_pill";
import * as compose_ui from "./compose_ui";
import * as composebox_typeahead from "./composebox_typeahead"; import * as composebox_typeahead from "./composebox_typeahead";
import * as dark_theme from "./dark_theme"; import * as dark_theme from "./dark_theme";
import * as emoji from "./emoji"; import * as emoji from "./emoji";
@ -495,6 +496,7 @@ export function dispatch_normal_event(event) {
stream_settings_ui.remove_stream(stream.stream_id); stream_settings_ui.remove_stream(stream.stream_id);
if (was_subscribed) { if (was_subscribed) {
stream_list.remove_sidebar_row(stream.stream_id); stream_list.remove_sidebar_row(stream.stream_id);
compose_ui.update_stream_dropdown_options();
} }
settings_streams.update_default_streams_table(); settings_streams.update_default_streams_table();
stream_data.remove_default_stream(stream.stream_id); stream_data.remove_default_stream(stream.stream_id);

View File

@ -2,6 +2,7 @@ import $ from "jquery";
import * as blueslip from "./blueslip"; import * as blueslip from "./blueslip";
import * as color_data from "./color_data"; import * as color_data from "./color_data";
import * as compose_ui from "./compose_ui";
import * as message_lists from "./message_lists"; import * as message_lists from "./message_lists";
import * as message_view_header from "./message_view_header"; import * as message_view_header from "./message_view_header";
import * as narrow_state from "./narrow_state"; import * as narrow_state from "./narrow_state";
@ -62,6 +63,8 @@ export function update_property(stream_id, property, value, other_values) {
break; break;
case "name": case "name":
stream_settings_ui.update_stream_name(sub, value); stream_settings_ui.update_stream_name(sub, value);
compose_ui.update_stream_dropdown_options();
compose_ui.possibly_update_dropdown_selection(sub.name, value);
break; break;
case "description": case "description":
stream_settings_ui.update_stream_description( stream_settings_ui.update_stream_description(
@ -83,6 +86,8 @@ export function update_property(stream_id, property, value, other_values) {
history_public_to_subscribers: other_values.history_public_to_subscribers, history_public_to_subscribers: other_values.history_public_to_subscribers,
is_web_public: other_values.is_web_public, is_web_public: other_values.is_web_public,
}); });
// Force a re-render to get the right privacy icon
compose_ui.possibly_update_dropdown_selection(sub.name, sub.name);
break; break;
case "stream_post_policy": case "stream_post_policy":
stream_settings_ui.update_stream_post_policy(sub, value); stream_settings_ui.update_stream_post_policy(sub, value);
@ -127,6 +132,7 @@ export function mark_subscribed(sub, subscribers, color) {
stream_settings_ui.set_color(sub.stream_id, color); stream_settings_ui.set_color(sub.stream_id, color);
} }
stream_data.subscribe_myself(sub); stream_data.subscribe_myself(sub);
compose_ui.update_stream_dropdown_options();
if (subscribers) { if (subscribers) {
peer_data.set_subscribers(sub.stream_id, subscribers); peer_data.set_subscribers(sub.stream_id, subscribers);
} }
@ -156,6 +162,7 @@ export function mark_unsubscribed(sub) {
return; return;
} else if (sub.subscribed) { } else if (sub.subscribed) {
stream_data.unsubscribe_myself(sub); stream_data.unsubscribe_myself(sub);
compose_ui.update_stream_dropdown_options();
if (overlays.streams_open()) { if (overlays.streams_open()) {
stream_settings_ui.update_settings_for_unsubscribed(sub); stream_settings_ui.update_settings_for_unsubscribed(sub);
} }

View File

@ -56,6 +56,7 @@ const compose_state = zrequire("compose_state");
const compose = zrequire("compose"); const compose = zrequire("compose");
const echo = zrequire("echo"); const echo = zrequire("echo");
const people = zrequire("people"); const people = zrequire("people");
const stream_bar = zrequire("stream_bar");
const stream_data = zrequire("stream_data"); const stream_data = zrequire("stream_data");
function reset_jquery() { function reset_jquery() {
@ -304,10 +305,10 @@ test_ui("send_message", ({override, override_rewire, mock_template}) => {
test_ui("enter_with_preview_open", ({override, override_rewire}) => { test_ui("enter_with_preview_open", ({override, override_rewire}) => {
mock_banners(); mock_banners();
$("#compose-textarea").toggleClass = noop; $("#compose-textarea").toggleClass = noop;
override_rewire(stream_bar, "decorate", noop);
mock_stream_header_colorblock(); mock_stream_header_colorblock();
compose_actions.open_compose_stream_dropup = noop; compose_actions.open_compose_stream_dropup = noop;
compose.update_on_recipient_change = noop; compose.update_on_recipient_change = noop;
compose_ui.on_compose_select_stream_update = noop;
let stream_value = ""; let stream_value = "";
compose_ui.compose_stream_widget = { compose_ui.compose_stream_widget = {
value() { value() {
@ -367,6 +368,7 @@ test_ui("enter_with_preview_open", ({override, override_rewire}) => {
test_ui("finish", ({override, override_rewire}) => { test_ui("finish", ({override, override_rewire}) => {
mock_banners(); mock_banners();
mock_stream_header_colorblock(); mock_stream_header_colorblock();
override_rewire(stream_bar, "decorate", noop);
override_rewire(compose_banner, "clear_message_sent_banners", () => {}); override_rewire(compose_banner, "clear_message_sent_banners", () => {});
override(reminder, "is_deferred_delivery", () => false); override(reminder, "is_deferred_delivery", () => false);
@ -764,6 +766,7 @@ test_ui("on_events", ({override}) => {
test_ui("create_message_object", ({override, override_rewire}) => { test_ui("create_message_object", ({override, override_rewire}) => {
mock_stream_header_colorblock(); mock_stream_header_colorblock();
override_rewire(stream_bar, "decorate", noop);
compose_state.set_stream_name("social"); compose_state.set_stream_name("social");
$("#stream_message_recipient_topic").val("lunch"); $("#stream_message_recipient_topic").val("lunch");

View File

@ -12,6 +12,7 @@ const compose_pm_pill = mock_esm("../src/compose_pm_pill");
const compose_state = zrequire("compose_state"); const compose_state = zrequire("compose_state");
const compose_fade = zrequire("compose_fade"); const compose_fade = zrequire("compose_fade");
const compose_ui = zrequire("compose_ui"); const compose_ui = zrequire("compose_ui");
const stream_bar = zrequire("stream_bar");
const noop = () => {}; const noop = () => {};
@ -37,12 +38,12 @@ run_test("private_message_recipient", ({override}) => {
assert.equal(compose_state.private_message_recipient(), "fred@fred.org"); assert.equal(compose_state.private_message_recipient(), "fred@fred.org");
}); });
run_test("has_full_recipient", ({override}) => { run_test("has_full_recipient", ({override, override_rewire}) => {
mock_stream_header_colorblock(); mock_stream_header_colorblock();
$(`#compose_banners .topic_resolved`).remove = noop; $(`#compose_banners .topic_resolved`).remove = noop;
compose_fade.update_all = noop; compose_fade.update_all = noop;
$(".narrow_to_compose_recipients").toggleClass = noop; $(".narrow_to_compose_recipients").toggleClass = noop;
compose_ui.on_compose_select_stream_update = noop; override_rewire(stream_bar, "decorate", noop);
let emails; let emails;
override(compose_pm_pill, "set_from_emails", (value) => { override(compose_pm_pill, "set_from_emails", (value) => {

View File

@ -38,6 +38,7 @@ const typeahead_helper = zrequire("typeahead_helper");
const muted_users = zrequire("muted_users"); const muted_users = zrequire("muted_users");
const people = zrequire("people"); const people = zrequire("people");
const user_groups = zrequire("user_groups"); const user_groups = zrequire("user_groups");
const stream_bar = zrequire("stream_bar");
const stream_data = zrequire("stream_data"); const stream_data = zrequire("stream_data");
const compose = zrequire("compose"); const compose = zrequire("compose");
const compose_pm_pill = zrequire("compose_pm_pill"); const compose_pm_pill = zrequire("compose_pm_pill");
@ -675,7 +676,7 @@ function sorted_names_from(subs) {
test("initialize", ({override, override_rewire, mock_template}) => { test("initialize", ({override, override_rewire, mock_template}) => {
mock_stream_header_colorblock(); mock_stream_header_colorblock();
compose.update_on_recipient_change = noop; compose.update_on_recipient_change = noop;
compose_ui.on_compose_select_stream_update = noop; override_rewire(stream_bar, "decorate", noop);
let pill_items = []; let pill_items = [];
let cleared = false; let cleared = false;
@ -1722,6 +1723,7 @@ test("PM recipients sorted according to stream / topic being viewed", ({override
stream_id === denmark_stream.stream_id && user_id === cordelia.user_id, stream_id === denmark_stream.stream_id && user_id === cordelia.user_id,
); );
mock_stream_header_colorblock(); mock_stream_header_colorblock();
override_rewire(stream_bar, "decorate", noop);
// When viewing no stream, sorting is alphabetical // When viewing no stream, sorting is alphabetical
compose_state.set_stream_name(""); compose_state.set_stream_name("");

View File

@ -23,6 +23,7 @@ const stream_list = mock_esm("../src/stream_list");
const stream_settings_ui = mock_esm("../src/stream_settings_ui"); const stream_settings_ui = mock_esm("../src/stream_settings_ui");
message_lists.current = {}; message_lists.current = {};
const compose_ui = zrequire("compose_ui");
const peer_data = zrequire("peer_data"); const peer_data = zrequire("peer_data");
const people = zrequire("people"); const people = zrequire("people");
const server_events_dispatch = zrequire("server_events_dispatch"); const server_events_dispatch = zrequire("server_events_dispatch");
@ -197,7 +198,9 @@ test("stream create", ({override}) => {
assert.deepEqual(sub_store.get(102).name, "test"); assert.deepEqual(sub_store.get(102).name, "test");
}); });
test("stream delete (normal)", ({override}) => { test("stream delete (normal)", ({override, override_rewire}) => {
override_rewire(compose_ui, "update_stream_dropdown_options", noop);
const event = event_fixtures.stream__delete; const event = event_fixtures.stream__delete;
for (const stream of event.streams) { for (const stream of event.streams) {
@ -238,7 +241,9 @@ test("stream delete (normal)", ({override}) => {
assert.equal(removed_sidebar_rows, 1); assert.equal(removed_sidebar_rows, 1);
}); });
test("stream delete (special streams)", ({override}) => { test("stream delete (special streams)", ({override, override_rewire}) => {
override_rewire(compose_ui, "update_stream_dropdown_options", noop);
const event = event_fixtures.stream__delete; const event = event_fixtures.stream__delete;
for (const stream of event.streams) { for (const stream of event.streams) {

View File

@ -17,6 +17,7 @@ const compose_fade = zrequire("compose_fade");
const compose_state = zrequire("compose_state"); const compose_state = zrequire("compose_state");
const compose_ui = zrequire("compose_ui"); const compose_ui = zrequire("compose_ui");
const sub_store = zrequire("sub_store"); const sub_store = zrequire("sub_store");
const stream_bar = zrequire("stream_bar");
const stream_data = zrequire("stream_data"); const stream_data = zrequire("stream_data");
let stream_value = ""; let stream_value = "";
@ -167,7 +168,7 @@ test("snapshot_message", ({override_rewire}) => {
override_rewire(user_pill, "get_user_ids", () => [aaron.user_id]); override_rewire(user_pill, "get_user_ids", () => [aaron.user_id]);
override_rewire(compose_pm_pill, "set_from_emails", noop); override_rewire(compose_pm_pill, "set_from_emails", noop);
mock_banners(); mock_banners();
compose_ui.on_compose_select_stream_update = noop; override_rewire(stream_bar, "decorate", noop);
stream_data.get_sub = (stream_name) => { stream_data.get_sub = (stream_name) => {
assert.equal(stream_name, "stream"); assert.equal(stream_name, "stream");

View File

@ -41,6 +41,7 @@ const peer_data = zrequire("peer_data");
const people = zrequire("people"); const people = zrequire("people");
const stream_data = zrequire("stream_data"); const stream_data = zrequire("stream_data");
const stream_events = zrequire("stream_events"); const stream_events = zrequire("stream_events");
const compose_ui = zrequire("compose_ui");
const george = { const george = {
email: "george@zulip.com", email: "george@zulip.com",
@ -86,7 +87,10 @@ function test(label, f) {
}); });
} }
test("update_property", ({override}) => { test("update_property", ({override, override_rewire}) => {
override_rewire(compose_ui, "update_stream_dropdown_options", noop);
override_rewire(compose_ui, "possibly_update_dropdown_selection", noop);
const sub = {...frontend}; const sub = {...frontend};
stream_data.add_sub(sub); stream_data.add_sub(sub);
@ -276,10 +280,11 @@ test("marked_subscribed (error)", () => {
blueslip.reset(); blueslip.reset();
}); });
test("marked_subscribed (normal)", ({override}) => { test("marked_subscribed (normal)", ({override, override_rewire}) => {
const sub = {...frontend}; const sub = {...frontend};
stream_data.add_sub(sub); stream_data.add_sub(sub);
override(stream_color, "update_stream_color", noop); override(stream_color, "update_stream_color", noop);
override_rewire(compose_ui, "update_stream_dropdown_options", noop);
narrow_to_frontend(); narrow_to_frontend();
@ -314,10 +319,11 @@ test("marked_subscribed (normal)", ({override}) => {
narrow_state.reset_current_filter(); narrow_state.reset_current_filter();
}); });
test("marked_subscribed (color)", ({override}) => { test("marked_subscribed (color)", ({override, override_rewire}) => {
override(stream_list, "add_sidebar_row", noop); override(stream_list, "add_sidebar_row", noop);
override(stream_list, "update_subscribe_to_more_streams_link", noop); override(stream_list, "update_subscribe_to_more_streams_link", noop);
override(unread_ui, "update_unread_counts", noop); override(unread_ui, "update_unread_counts", noop);
override_rewire(compose_ui, "update_stream_dropdown_options", noop);
const sub = { const sub = {
subscribed: false, subscribed: false,
@ -346,10 +352,11 @@ test("marked_subscribed (color)", ({override}) => {
} }
}); });
test("marked_subscribed (emails)", ({override}) => { test("marked_subscribed (emails)", ({override, override_rewire}) => {
const sub = {...frontend}; const sub = {...frontend};
stream_data.add_sub(sub); stream_data.add_sub(sub);
override(stream_color, "update_stream_color", noop); override(stream_color, "update_stream_color", noop);
override_rewire(compose_ui, "update_stream_dropdown_options", noop);
// Test assigning subscriber emails // Test assigning subscriber emails
// narrow state is undefined // narrow state is undefined
@ -373,7 +380,7 @@ test("marked_subscribed (emails)", ({override}) => {
assert.deepEqual(sub, args.sub); assert.deepEqual(sub, args.sub);
}); });
test("mark_unsubscribed (update_settings_for_unsubscribed)", ({override}) => { test("mark_unsubscribed (update_settings_for_unsubscribed)", ({override, override_rewire}) => {
// Test unsubscribe // Test unsubscribe
const sub = {...dev_help}; const sub = {...dev_help};
stream_data.add_sub(sub); stream_data.add_sub(sub);
@ -388,12 +395,13 @@ test("mark_unsubscribed (update_settings_for_unsubscribed)", ({override}) => {
$("#streams_overlay_container .stream-row:not(.notdisplayed)").length = 0; $("#streams_overlay_container .stream-row:not(.notdisplayed)").length = 0;
override_rewire(compose_ui, "update_stream_dropdown_options", noop);
stream_events.mark_unsubscribed(sub); stream_events.mark_unsubscribed(sub);
const args = stub.get_args("sub"); const args = stub.get_args("sub");
assert.deepEqual(args.sub, sub); assert.deepEqual(args.sub, sub);
}); });
test("mark_unsubscribed (render_title_area)", ({override}) => { test("mark_unsubscribed (render_title_area)", ({override, override_rewire}) => {
const sub = {...frontend, subscribed: true}; const sub = {...frontend, subscribed: true};
stream_data.add_sub(sub); stream_data.add_sub(sub);
@ -414,6 +422,7 @@ test("mark_unsubscribed (render_title_area)", ({override}) => {
$("#streams_overlay_container .stream-row:not(.notdisplayed)").length = 0; $("#streams_overlay_container .stream-row:not(.notdisplayed)").length = 0;
override_rewire(compose_ui, "update_stream_dropdown_options", noop);
stream_events.mark_unsubscribed(sub); stream_events.mark_unsubscribed(sub);
assert.equal(message_view_header_stub.num_calls, 1); assert.equal(message_view_header_stub.num_calls, 1);