diff --git a/frontend_tests/node_tests/compose.js b/frontend_tests/node_tests/compose.js index f19de2756d..d7fe5c0362 100644 --- a/frontend_tests/node_tests/compose.js +++ b/frontend_tests/node_tests/compose.js @@ -29,8 +29,8 @@ const rendered_markdown = mock_esm("../../static/js/rendered_markdown"); const resize = mock_esm("../../static/js/resize"); const sent_messages = mock_esm("../../static/js/sent_messages"); const server_events = mock_esm("../../static/js/server_events"); -const stream_edit = mock_esm("../../static/js/stream_edit"); const stream_settings_ui = mock_esm("../../static/js/stream_settings_ui"); +const stream_subscribers_ui = mock_esm("../../static/js/stream_subscribers_ui"); const transmit = mock_esm("../../static/js/transmit"); const compose_closed_ui = zrequire("compose_closed_ui"); @@ -625,7 +625,7 @@ test_ui("on_events", ({override}) => { people.add_active_user(mentioned); let invite_user_to_stream_called = false; - override(stream_edit, "invite_user_to_stream", (user_ids, sub, success) => { + override(stream_subscribers_ui, "invite_user_to_stream", (user_ids, sub, success) => { invite_user_to_stream_called = true; assert.deepEqual(user_ids, [mentioned.user_id]); assert.equal(sub, subscription); diff --git a/frontend_tests/node_tests/stream_edit.js b/frontend_tests/node_tests/stream_edit.js index 2def439f61..27c40bd014 100644 --- a/frontend_tests/node_tests/stream_edit.js +++ b/frontend_tests/node_tests/stream_edit.js @@ -40,6 +40,7 @@ const stream_pill = zrequire("stream_pill"); const user_groups = zrequire("user_groups"); const user_group_pill = zrequire("user_group_pill"); const user_pill = zrequire("user_pill"); +const stream_subscribers_ui = zrequire("stream_subscribers_ui"); const stream_ui_updates = zrequire("stream_ui_updates"); const settings_config = zrequire("settings_config"); @@ -110,6 +111,7 @@ for (const sub of subs) { function test_ui(label, f) { run_test(label, ({override, mock_template}) => { page_params.user_id = me.user_id; + stream_subscribers_ui.initialize(); stream_edit.initialize(); f({override, mock_template}); }); @@ -180,7 +182,7 @@ test_ui("subscriber_pills", ({override, mock_template}) => { let expected_user_ids = []; let input_typeahead_called = false; let add_subscribers_request = false; - override(stream_edit, "invite_user_to_stream", (user_ids, sub) => { + override(stream_subscribers_ui, "invite_user_to_stream", (user_ids, sub) => { assert.equal(sub.stream_id, denmark.stream_id); assert.deepEqual(user_ids.sort(), expected_user_ids.sort()); add_subscribers_request = true; @@ -266,7 +268,7 @@ test_ui("subscriber_pills", ({override, mock_template}) => { (function test_updater() { function number_of_pills() { - const pills = stream_edit.pill_widget.items(); + const pills = stream_subscribers_ui.pill_widget.items(); return pills.length; } diff --git a/static/js/compose.js b/static/js/compose.js index 515978b390..42ab16c587 100644 --- a/static/js/compose.js +++ b/static/js/compose.js @@ -28,8 +28,8 @@ import * as rows from "./rows"; import * as sent_messages from "./sent_messages"; import * as server_events from "./server_events"; import * as stream_data from "./stream_data"; -import * as stream_edit from "./stream_edit"; import * as stream_settings_ui from "./stream_settings_ui"; +import * as stream_subscribers_ui from "./stream_subscribers_ui"; import * as sub_store from "./sub_store"; import * as transmit from "./transmit"; import * as ui_report from "./ui_report"; @@ -495,7 +495,7 @@ export function initialize() { const sub = sub_store.get(stream_id); - stream_edit.invite_user_to_stream([user_id], sub, success, xhr_failure); + stream_subscribers_ui.invite_user_to_stream([user_id], sub, success, xhr_failure); }); $("#compose_invite_users").on("click", ".compose_invite_close", (event) => { diff --git a/static/js/stream_edit.js b/static/js/stream_edit.js index d9dcf1058f..a0a928d016 100644 --- a/static/js/stream_edit.js +++ b/static/js/stream_edit.js @@ -1,12 +1,9 @@ import $ from "jquery"; import render_settings_deactivation_stream_modal from "../templates/confirm_dialog/confirm_deactivate_stream.hbs"; -import render_unsubscribe_private_stream_modal from "../templates/confirm_dialog/confirm_unsubscribe_private_stream.hbs"; import render_change_stream_info_modal from "../templates/stream_settings/change_stream_info_modal.hbs"; import render_stream_description from "../templates/stream_settings/stream_description.hbs"; -import render_stream_member_list_entry from "../templates/stream_settings/stream_member_list_entry.hbs"; import render_stream_settings from "../templates/stream_settings/stream_settings.hbs"; -import render_stream_subscription_request_result from "../templates/stream_settings/stream_subscription_request_result.hbs"; import render_stream_types from "../templates/stream_settings/stream_types.hbs"; import * as blueslip from "./blueslip"; @@ -17,32 +14,23 @@ import * as confirm_dialog from "./confirm_dialog"; import * as dialog_widget from "./dialog_widget"; import * as hash_util from "./hash_util"; import {$t, $t_html} from "./i18n"; -import * as input_pill from "./input_pill"; -import * as ListWidget from "./list_widget"; import * as narrow_state from "./narrow_state"; import {page_params} from "./page_params"; -import * as peer_data from "./peer_data"; -import * as people from "./people"; -import * as pill_typeahead from "./pill_typeahead"; import * as settings_config from "./settings_config"; -import * as settings_data from "./settings_data"; import * as settings_ui from "./settings_ui"; import * as stream_color from "./stream_color"; import * as stream_data from "./stream_data"; -import * as stream_pill from "./stream_pill"; import * as stream_settings_containers from "./stream_settings_containers"; import * as stream_settings_data from "./stream_settings_data"; import * as stream_settings_ui from "./stream_settings_ui"; +import * as stream_subscribers_ui from "./stream_subscribers_ui"; import * as stream_ui_updates from "./stream_ui_updates"; import * as sub_store from "./sub_store"; import * as ui from "./ui"; import * as ui_report from "./ui_report"; -import * as user_group_pill from "./user_group_pill"; -import * as user_pill from "./user_pill"; import {user_settings} from "./user_settings"; import * as util from "./util"; -export let pill_widget; export let toggler; export let select_tab = "personal_settings"; @@ -175,16 +163,6 @@ export function open_edit_panel_empty() { setup_subscriptions_tab_hash(tab_key); } -function format_member_list_elem(person) { - return render_stream_member_list_entry({ - name: person.full_name, - user_id: person.user_id, - email: settings_data.email_for_user_settings(person), - displaying_for_admin: page_params.is_admin, - show_email: settings_data.show_email(), - }); -} - export function update_stream_name(sub, new_name) { const edit_container = stream_settings_containers.get_edit_container(sub); edit_container.find(".email-address").text(sub.email_address); @@ -200,162 +178,6 @@ export function update_stream_description(sub) { edit_container.find(".stream-description").html(html); } -export function invite_user_to_stream(user_ids, sub, success, failure) { - // TODO: use stream_id when backend supports it - const stream_name = sub.name; - return channel.post({ - url: "/json/users/me/subscriptions", - data: { - subscriptions: JSON.stringify([{name: stream_name}]), - principals: JSON.stringify(user_ids), - }, - success, - error: failure, - }); -} - -function show_stream_subscription_request_result({ - message, - add_class, - remove_class, - subscribed_users, - already_subscribed_users, - ignored_deactivated_users, -}) { - const stream_subscription_req_result_elem = $( - ".stream_subscription_request_result", - ).expectOne(); - const html = render_stream_subscription_request_result({ - message, - subscribed_users, - already_subscribed_users, - ignored_deactivated_users, - }); - ui.get_content_element(stream_subscription_req_result_elem).html(html); - if (add_class) { - stream_subscription_req_result_elem.addClass(add_class); - } - if (remove_class) { - stream_subscription_req_result_elem.removeClass(remove_class); - } -} - -function submit_add_subscriber_form(e) { - const sub = get_sub_for_target(e.target); - if (!sub) { - blueslip.error(".subscriber_list_add form submit fails"); - return; - } - - let user_ids = user_pill.get_user_ids(pill_widget); - user_ids = user_ids.concat(stream_pill.get_user_ids(pill_widget)); - user_ids = user_ids.concat(user_group_pill.get_user_ids(pill_widget)); - const deactivated_users = new Set(); - user_ids = user_ids.filter((user_id) => { - if (!people.is_person_active(user_id)) { - deactivated_users.add(user_id); - return false; - } - return true; - }); - - user_ids = new Set(user_ids); - - if (user_ids.has(page_params.user_id) && sub.subscribed) { - // We don't want to send a request to subscribe ourselves - // if we are already subscribed to this stream. This - // case occurs when creating user pills from a stream. - user_ids.delete(page_params.user_id); - } - let ignored_deactivated_users; - if (deactivated_users.size > 0) { - ignored_deactivated_users = Array.from(deactivated_users); - ignored_deactivated_users = ignored_deactivated_users.map((user_id) => - people.get_by_user_id(user_id), - ); - } - if (user_ids.size === 0) { - show_stream_subscription_request_result({ - message: $t({defaultMessage: "No user to subscribe."}), - add_class: "text-error", - remove_class: "text-success", - ignored_deactivated_users, - }); - return; - } - user_ids = Array.from(user_ids); - - function invite_success(data) { - pill_widget.clear(); - const subscribed_users = Object.keys(data.subscribed).map((email) => - people.get_by_email(email), - ); - const already_subscribed_users = Object.keys(data.already_subscribed).map((email) => - people.get_by_email(email), - ); - - show_stream_subscription_request_result({ - add_class: "text-success", - remove_class: "text-error", - subscribed_users, - already_subscribed_users, - ignored_deactivated_users, - }); - } - - function invite_failure(xhr) { - const error = JSON.parse(xhr.responseText); - show_stream_subscription_request_result({ - message: error.msg, - add_class: "text-error", - remove_class: "text-success", - }); - } - - invite_user_to_stream(user_ids, sub, invite_success, invite_failure); -} - -export function remove_user_from_stream(user_id, sub, success, failure) { - // TODO: use stream_id when backend supports it - const stream_name = sub.name; - return channel.del({ - url: "/json/users/me/subscriptions", - data: {subscriptions: JSON.stringify([stream_name]), principals: JSON.stringify([user_id])}, - success, - error: failure, - }); -} - -export function create_item_from_text(text, current_items) { - const funcs = [ - stream_pill.create_item_from_stream_name, - user_group_pill.create_item_from_group_name, - user_pill.create_item_from_email, - ]; - for (const func of funcs) { - const item = func(text, current_items); - if (item) { - return item; - } - } - return undefined; -} - -export function get_text_from_item(item) { - const funcs = [ - stream_pill.get_stream_name_from_item, - user_group_pill.get_group_name_from_item, - user_pill.get_email_from_item, - ]; - for (const func of funcs) { - const text = func(item); - if (text) { - return text; - } - } - return undefined; -} - function show_subscription_settings(sub) { const edit_container = stream_settings_containers.get_edit_container(sub); @@ -372,58 +194,7 @@ function show_subscription_settings(sub) { stream_ui_updates.initialize_cant_subscribe_popover(sub); } - enable_subscriber_management({sub, parent_container: edit_container}); -} - -function enable_subscriber_management({sub, parent_container}) { - const stream_id = sub.stream_id; - - const pill_container = parent_container.find(".pill-container"); - - pill_widget = input_pill.create({ - container: pill_container, - create_item_from_text, - get_text_from_item, - }); - - const user_ids = peer_data.get_subscribers(stream_id); - const users = people.get_users_from_ids(user_ids); - people.sort_but_pin_current_user_on_top(users); - - function get_users_for_subscriber_typeahead() { - const potential_subscribers = peer_data.potential_subscribers(stream_id); - return user_pill.filter_taken_users(potential_subscribers, pill_widget); - } - - const list_container = parent_container.find(".subscriber_table"); - list_container.empty(); - - const simplebar_container = parent_container.find(".subscriber_list_container"); - - ListWidget.create(list_container, users, { - name: "stream_subscribers/" + stream_id, - modifier(item) { - return format_member_list_elem(item); - }, - filter: { - element: $(`[data-stream-id='${CSS.escape(stream_id)}'] .search`), - predicate(person, value) { - const matcher = people.build_person_matcher(value); - const match = matcher(person); - - return match; - }, - }, - simplebar_container, - }); - - const opts = { - user_source: get_users_for_subscriber_typeahead, - stream: true, - user_group: true, - user: true, - }; - pill_typeahead.set_up(pill_container.find(".input"), pill_widget, opts); + stream_subscribers_ui.enable_subscriber_management({sub, parent_container: edit_container}); } export function is_notification_setting(setting_label) { @@ -837,76 +608,6 @@ export function initialize() { stream_setting_changed, ); - $("#subscriptions_table").on("keyup", ".subscriber_list_add form", (e) => { - if (e.key === "Enter") { - e.preventDefault(); - submit_add_subscriber_form(e); - } - }); - - $("#subscriptions_table").on("submit", ".subscriber_list_add form", (e) => { - e.preventDefault(); - submit_add_subscriber_form(e); - }); - - $("#subscriptions_table").on("submit", ".subscriber_list_remove form", (e) => { - e.preventDefault(); - - const list_entry = $(e.target).closest("tr"); - const target_user_id = Number.parseInt(list_entry.attr("data-subscriber-id"), 10); - - const sub = get_sub_for_target(e.target); - if (!sub) { - blueslip.error(".subscriber_list_remove form submit fails"); - return; - } - let message; - - function removal_success(data) { - if (data.removed.length > 0) { - // Remove the user from the subscriber list. - list_entry.remove(); - message = $t({defaultMessage: "Unsubscribed successfully!"}); - // The rest of the work is done via the subscription -> remove event we will get - } else { - message = $t({defaultMessage: "User is already not subscribed."}); - } - show_stream_subscription_request_result({ - message, - add_class: "text-success", - remove_class: "text-remove", - }); - } - - function removal_failure() { - show_stream_subscription_request_result({ - message: $t({defaultMessage: "Error removing user from this stream."}), - add_class: "text-error", - remove_class: "text-success", - }); - } - - function remove_user_from_private_stream() { - remove_user_from_stream(target_user_id, sub, removal_success, removal_failure); - } - - if (sub.invite_only && people.is_my_user_id(target_user_id)) { - const html_body = render_unsubscribe_private_stream_modal(); - - confirm_dialog.launch({ - html_heading: $t_html( - {defaultMessage: "Unsubscribe from {stream_name}"}, - {stream_name: sub.name}, - ), - html_body, - on_click: remove_user_from_private_stream, - }); - return; - } - - remove_user_from_stream(target_user_id, sub, removal_success, removal_failure); - }); - // This handler isn't part of the normal edit interface; it's the convenient // checkmark in the subscriber list. $("#subscriptions_table").on("click", ".sub_unsub_button", (e) => { diff --git a/static/js/stream_subscribers_ui.js b/static/js/stream_subscribers_ui.js new file mode 100644 index 0000000000..2a8a17a63c --- /dev/null +++ b/static/js/stream_subscribers_ui.js @@ -0,0 +1,336 @@ +import $ from "jquery"; + +import render_unsubscribe_private_stream_modal from "../templates/confirm_dialog/confirm_unsubscribe_private_stream.hbs"; +import render_stream_member_list_entry from "../templates/stream_settings/stream_member_list_entry.hbs"; +import render_stream_subscription_request_result from "../templates/stream_settings/stream_subscription_request_result.hbs"; + +import * as blueslip from "./blueslip"; +import * as channel from "./channel"; +import * as confirm_dialog from "./confirm_dialog"; +import {$t, $t_html} from "./i18n"; +import * as input_pill from "./input_pill"; +import * as ListWidget from "./list_widget"; +import {page_params} from "./page_params"; +import * as peer_data from "./peer_data"; +import * as people from "./people"; +import * as pill_typeahead from "./pill_typeahead"; +import * as settings_data from "./settings_data"; +import * as stream_pill from "./stream_pill"; +import * as sub_store from "./sub_store"; +import * as ui from "./ui"; +import * as user_group_pill from "./user_group_pill"; +import * as user_pill from "./user_pill"; + +export let pill_widget; + +function create_item_from_text(text, current_items) { + const funcs = [ + stream_pill.create_item_from_stream_name, + user_group_pill.create_item_from_group_name, + user_pill.create_item_from_email, + ]; + for (const func of funcs) { + const item = func(text, current_items); + if (item) { + return item; + } + } + return undefined; +} + +function get_text_from_item(item) { + const funcs = [ + stream_pill.get_stream_name_from_item, + user_group_pill.get_group_name_from_item, + user_pill.get_email_from_item, + ]; + for (const func of funcs) { + const text = func(item); + if (text) { + return text; + } + } + return undefined; +} + +function format_member_list_elem(person) { + return render_stream_member_list_entry({ + name: person.full_name, + user_id: person.user_id, + email: settings_data.email_for_user_settings(person), + displaying_for_admin: page_params.is_admin, + show_email: settings_data.show_email(), + }); +} + +function get_stream_id(target) { + // TODO: Use more precise selector. + const row = $(target).closest( + ".stream-row, .stream_settings_header, .subscription_settings, .save-button", + ); + return Number.parseInt(row.attr("data-stream-id"), 10); +} + +function get_sub_for_target(target) { + const stream_id = get_stream_id(target); + if (!stream_id) { + blueslip.error("Cannot find stream id for target"); + return undefined; + } + + const sub = sub_store.get(stream_id); + if (!sub) { + blueslip.error("get_sub_for_target() failed id lookup: " + stream_id); + return undefined; + } + return sub; +} + +function show_stream_subscription_request_result({ + message, + add_class, + remove_class, + subscribed_users, + already_subscribed_users, + ignored_deactivated_users, +}) { + const stream_subscription_req_result_elem = $( + ".stream_subscription_request_result", + ).expectOne(); + const html = render_stream_subscription_request_result({ + message, + subscribed_users, + already_subscribed_users, + ignored_deactivated_users, + }); + ui.get_content_element(stream_subscription_req_result_elem).html(html); + if (add_class) { + stream_subscription_req_result_elem.addClass(add_class); + } + if (remove_class) { + stream_subscription_req_result_elem.removeClass(remove_class); + } +} + +export function enable_subscriber_management({sub, parent_container}) { + const stream_id = sub.stream_id; + + const pill_container = parent_container.find(".pill-container"); + + pill_widget = input_pill.create({ + container: pill_container, + create_item_from_text, + get_text_from_item, + }); + + const user_ids = peer_data.get_subscribers(stream_id); + const users = people.get_users_from_ids(user_ids); + people.sort_but_pin_current_user_on_top(users); + + function get_users_for_subscriber_typeahead() { + const potential_subscribers = peer_data.potential_subscribers(stream_id); + return user_pill.filter_taken_users(potential_subscribers, pill_widget); + } + + const list_container = parent_container.find(".subscriber_table"); + list_container.empty(); + + const simplebar_container = parent_container.find(".subscriber_list_container"); + + ListWidget.create(list_container, users, { + name: "stream_subscribers/" + stream_id, + modifier(item) { + return format_member_list_elem(item); + }, + filter: { + element: $(`[data-stream-id='${CSS.escape(stream_id)}'] .search`), + predicate(person, value) { + const matcher = people.build_person_matcher(value); + const match = matcher(person); + + return match; + }, + }, + simplebar_container, + }); + + const opts = { + user_source: get_users_for_subscriber_typeahead, + stream: true, + user_group: true, + user: true, + }; + pill_typeahead.set_up(pill_container.find(".input"), pill_widget, opts); +} + +export function invite_user_to_stream(user_ids, sub, success, failure) { + // TODO: use stream_id when backend supports it + const stream_name = sub.name; + return channel.post({ + url: "/json/users/me/subscriptions", + data: { + subscriptions: JSON.stringify([{name: stream_name}]), + principals: JSON.stringify(user_ids), + }, + success, + error: failure, + }); +} + +export function remove_user_from_stream(user_id, sub, success, failure) { + // TODO: use stream_id when backend supports it + const stream_name = sub.name; + return channel.del({ + url: "/json/users/me/subscriptions", + data: {subscriptions: JSON.stringify([stream_name]), principals: JSON.stringify([user_id])}, + success, + error: failure, + }); +} + +function submit_add_subscriber_form(e) { + const sub = get_sub_for_target(e.target); + if (!sub) { + blueslip.error(".subscriber_list_add form submit fails"); + return; + } + + let user_ids = user_pill.get_user_ids(pill_widget); + user_ids = user_ids.concat(stream_pill.get_user_ids(pill_widget)); + user_ids = user_ids.concat(user_group_pill.get_user_ids(pill_widget)); + const deactivated_users = new Set(); + user_ids = user_ids.filter((user_id) => { + if (!people.is_person_active(user_id)) { + deactivated_users.add(user_id); + return false; + } + return true; + }); + + user_ids = new Set(user_ids); + + if (user_ids.has(page_params.user_id) && sub.subscribed) { + // We don't want to send a request to subscribe ourselves + // if we are already subscribed to this stream. This + // case occurs when creating user pills from a stream. + user_ids.delete(page_params.user_id); + } + let ignored_deactivated_users; + if (deactivated_users.size > 0) { + ignored_deactivated_users = Array.from(deactivated_users); + ignored_deactivated_users = ignored_deactivated_users.map((user_id) => + people.get_by_user_id(user_id), + ); + } + if (user_ids.size === 0) { + show_stream_subscription_request_result({ + message: $t({defaultMessage: "No user to subscribe."}), + add_class: "text-error", + remove_class: "text-success", + ignored_deactivated_users, + }); + return; + } + user_ids = Array.from(user_ids); + + function invite_success(data) { + pill_widget.clear(); + const subscribed_users = Object.keys(data.subscribed).map((email) => + people.get_by_email(email), + ); + const already_subscribed_users = Object.keys(data.already_subscribed).map((email) => + people.get_by_email(email), + ); + + show_stream_subscription_request_result({ + add_class: "text-success", + remove_class: "text-error", + subscribed_users, + already_subscribed_users, + ignored_deactivated_users, + }); + } + + function invite_failure(xhr) { + const error = JSON.parse(xhr.responseText); + show_stream_subscription_request_result({ + message: error.msg, + add_class: "text-error", + remove_class: "text-success", + }); + } + + invite_user_to_stream(user_ids, sub, invite_success, invite_failure); +} + +export function initialize() { + $("#subscriptions_table").on("keyup", ".subscriber_list_add form", (e) => { + if (e.key === "Enter") { + e.preventDefault(); + submit_add_subscriber_form(e); + } + }); + + $("#subscriptions_table").on("submit", ".subscriber_list_add form", (e) => { + e.preventDefault(); + submit_add_subscriber_form(e); + }); + + $("#subscriptions_table").on("submit", ".subscriber_list_remove form", (e) => { + e.preventDefault(); + + const list_entry = $(e.target).closest("tr"); + const target_user_id = Number.parseInt(list_entry.attr("data-subscriber-id"), 10); + + const sub = get_sub_for_target(e.target); + if (!sub) { + blueslip.error(".subscriber_list_remove form submit fails"); + return; + } + let message; + + function removal_success(data) { + if (data.removed.length > 0) { + // Remove the user from the subscriber list. + list_entry.remove(); + message = $t({defaultMessage: "Unsubscribed successfully!"}); + // The rest of the work is done via the subscription -> remove event we will get + } else { + message = $t({defaultMessage: "User is already not subscribed."}); + } + show_stream_subscription_request_result({ + message, + add_class: "text-success", + remove_class: "text-remove", + }); + } + + function removal_failure() { + show_stream_subscription_request_result({ + message: $t({defaultMessage: "Error removing user from this stream."}), + add_class: "text-error", + remove_class: "text-success", + }); + } + + function remove_user_from_private_stream() { + remove_user_from_stream(target_user_id, sub, removal_success, removal_failure); + } + + if (sub.invite_only && people.is_my_user_id(target_user_id)) { + const html_body = render_unsubscribe_private_stream_modal(); + + confirm_dialog.launch({ + html_heading: $t_html( + {defaultMessage: "Unsubscribe from {stream_name}"}, + {stream_name: sub.name}, + ), + html_body, + on_click: remove_user_from_private_stream, + }); + return; + } + + remove_user_from_stream(target_user_id, sub, removal_success, removal_failure); + }); +} diff --git a/static/js/ui_init.js b/static/js/ui_init.js index 414d4da45a..0f7a0707d3 100644 --- a/static/js/ui_init.js +++ b/static/js/ui_init.js @@ -81,6 +81,7 @@ import * as stream_data from "./stream_data"; import * as stream_edit from "./stream_edit"; import * as stream_list from "./stream_list"; import * as stream_settings_ui from "./stream_settings_ui"; +import * as stream_subscribers_ui from "./stream_subscribers_ui"; import * as timerender from "./timerender"; import * as tippyjs from "./tippyjs"; import * as topic_list from "./topic_list"; @@ -568,6 +569,7 @@ export function initialize_everything() { initialize_kitchen_sink_stuff(); echo.initialize(); stream_edit.initialize(); + stream_subscribers_ui.initialize(); stream_data.initialize(stream_data_params); pm_conversations.recent.initialize(pm_conversations_params); muted_topics.initialize(); diff --git a/static/js/user_profile.js b/static/js/user_profile.js index dd7b2ed3c1..e63e932202 100644 --- a/static/js/user_profile.js +++ b/static/js/user_profile.js @@ -20,7 +20,7 @@ import * as settings_account from "./settings_account"; import * as settings_data from "./settings_data"; import * as settings_profile_fields from "./settings_profile_fields"; import * as stream_data from "./stream_data"; -import * as stream_edit from "./stream_edit"; +import * as stream_subscribers_ui from "./stream_subscribers_ui"; import * as sub_store from "./sub_store"; import * as ui_report from "./ui_report"; import * as user_groups from "./user_groups"; @@ -213,7 +213,7 @@ function handle_remove_stream_subscription(target_user_id, sub, success, failure }); } else { // Unsubscribed by admin. - stream_edit.remove_user_from_stream(target_user_id, sub, success, failure); + stream_subscribers_ui.remove_user_from_stream(target_user_id, sub, success, failure); } } diff --git a/tools/test-js-with-node b/tools/test-js-with-node index 0f1b2f2cc1..8bb2cc9c0e 100755 --- a/tools/test-js-with-node +++ b/tools/test-js-with-node @@ -158,6 +158,7 @@ EXEMPT_FILES = { "static/js/stream_list.js", "static/js/stream_muting.js", "static/js/stream_popover.js", + "static/js/stream_subscribers_ui.js", "static/js/stream_ui_updates.js", "static/js/submessage.js", "static/js/stream_settings_ui.js",