diff --git a/frontend_tests/node_tests/settings_muted_users.js b/frontend_tests/node_tests/settings_muted_users.js new file mode 100644 index 0000000000..494e98c5d0 --- /dev/null +++ b/frontend_tests/node_tests/settings_muted_users.js @@ -0,0 +1,71 @@ +"use strict"; + +const {strict: assert} = require("assert"); + +const {mock_cjs, mock_esm, zrequire} = require("../zjsunit/namespace"); +const {run_test} = require("../zjsunit/test"); +const $ = require("../zjsunit/zjquery"); + +mock_cjs("jquery", $); +const muting_ui = mock_esm("../../static/js/muting_ui"); + +const settings_muted_users = zrequire("settings_muted_users"); +const muting = zrequire("muting"); + +const noop = () => {}; + +run_test("settings", (override) => { + muting.add_muted_user(5, 1577836800); + let populate_list_called = false; + override(settings_muted_users, "populate_list", () => { + const opts = muting.get_muted_users(); + assert.deepEqual(opts, [ + { + date_muted: 1577836800000, + date_muted_str: "Jan\u00A001,\u00A02020", + id: 5, + }, + ]); + populate_list_called = true; + }); + + settings_muted_users.reset(); + assert.equal(settings_muted_users.loaded, false); + + settings_muted_users.set_up(); + assert.equal(settings_muted_users.loaded, true); + assert(populate_list_called); + + const unmute_click_handler = $("body").get_on_handler("click", ".settings-unmute-user"); + assert.equal(typeof unmute_click_handler, "function"); + + const event = { + stopPropagation: noop, + }; + + const unmute_button = $.create("settings-unmute-user"); + const fake_row = $('tr[data-user-id="5"]'); + unmute_button.closest = (opts) => { + assert.equal(opts, "tr"); + return fake_row; + }; + + let row_attribute_fetched = false; + fake_row.attr = (opts) => { + if (opts === "data-user-id") { + row_attribute_fetched += 1; + return "5"; + } + throw new Error(`Unknown attribute ${opts}`); + }; + + let unmute_user_called = false; + muting_ui.unmute_user = (user_id) => { + assert.equal(user_id, 5); + unmute_user_called = true; + }; + + unmute_click_handler.call(unmute_button, event); + assert(unmute_user_called); + assert(row_attribute_fetched); +}); diff --git a/static/js/muting_ui.js b/static/js/muting_ui.js index 85f74a91c5..da183a508b 100644 --- a/static/js/muting_ui.js +++ b/static/js/muting_ui.js @@ -16,6 +16,7 @@ import * as people from "./people"; import * as popovers from "./popovers"; import * as recent_topics from "./recent_topics"; import * as settings_muted_topics from "./settings_muted_topics"; +import * as settings_muted_users from "./settings_muted_users"; import * as stream_data from "./stream_data"; import * as stream_list from "./stream_list"; import * as stream_popover from "./stream_popover"; @@ -195,7 +196,14 @@ export function unmute_user(user_id) { }); } +export function rerender_for_muted_user() { + if (overlays.settings_open() && settings_muted_users.loaded) { + settings_muted_users.populate_list(); + } +} + export function handle_user_updates(muted_user_ids) { popovers.hide_all(); muting.set_muted_users(muted_user_ids); + rerender_for_muted_user(); } diff --git a/static/js/settings_muted_users.js b/static/js/settings_muted_users.js new file mode 100644 index 0000000000..af03ca98d0 --- /dev/null +++ b/static/js/settings_muted_users.js @@ -0,0 +1,56 @@ +import $ from "jquery"; + +import render_muted_user_ui_row from "../templates/muted_user_ui_row.hbs"; + +import * as ListWidget from "./list_widget"; +import * as muting from "./muting"; +import * as muting_ui from "./muting_ui"; +import * as people from "./people"; +import * as ui from "./ui"; + +export let loaded = false; + +export function populate_list() { + const muted_users = muting.get_muted_users().map((user) => ({ + user_id: user.id, + user_name: people.get_full_name(user.id), + date_muted_str: user.date_muted_str, + })); + const muted_users_table = $("#muted_users_table"); + const $search_input = $("#muted_users_search"); + + ListWidget.create(muted_users_table, muted_users, { + name: "muted-users-list", + modifier(muted_users) { + return render_muted_user_ui_row({muted_users}); + }, + filter: { + element: $search_input, + predicate(item, value) { + return item.user_name.toLocaleLowerCase().includes(value); + }, + onupdate() { + ui.reset_scrollbar(muted_users_table.closest(".progressive-table-wrapper")); + }, + }, + parent_container: $("#muted-user-settings"), + simplebar_container: $("#muted-user-settings .progressive-table-wrapper"), + }); +} + +export function set_up() { + loaded = true; + $("body").on("click", ".settings-unmute-user", function (e) { + const $row = $(this).closest("tr"); + const user_id = Number.parseInt($row.attr("data-user-id"), 10); + + e.stopPropagation(); + muting_ui.unmute_user(user_id); + }); + + populate_list(); +} + +export function reset() { + loaded = false; +} diff --git a/static/js/settings_sections.js b/static/js/settings_sections.js index fd9e3f4515..f1c55fe3b6 100644 --- a/static/js/settings_sections.js +++ b/static/js/settings_sections.js @@ -9,6 +9,7 @@ import * as settings_exports from "./settings_exports"; import * as settings_invites from "./settings_invites"; import * as settings_linkifiers from "./settings_linkifiers"; import * as settings_muted_topics from "./settings_muted_topics"; +import * as settings_muted_users from "./settings_muted_users"; import * as settings_notifications from "./settings_notifications"; import * as settings_org from "./settings_org"; import * as settings_playgrounds from "./settings_playgrounds"; @@ -51,6 +52,7 @@ export function initialize() { load_func_dict.set("alert-words", alert_words_ui.set_up_alert_words); load_func_dict.set("uploaded-files", attachments_ui.set_up_attachments); load_func_dict.set("muted-topics", settings_muted_topics.set_up); + load_func_dict.set("muted-users", settings_muted_users.set_up); // org load_func_dict.set("org_misc", settings_org.set_up); @@ -99,5 +101,6 @@ export function reset_sections() { settings_streams.reset(); settings_user_groups.reset(); settings_muted_topics.reset(); + settings_muted_users.reset(); // settings_users doesn't need a reset() } diff --git a/static/templates/muted_user_ui_row.hbs b/static/templates/muted_user_ui_row.hbs new file mode 100644 index 0000000000..dc6ff8fcbb --- /dev/null +++ b/static/templates/muted_user_ui_row.hbs @@ -0,0 +1,9 @@ +{{#with muted_users}} + + {{user_name}} + {{date_muted_str}} + + {{t "Unmute" }} + + +{{/with}} diff --git a/static/templates/settings/muted_users_settings.hbs b/static/templates/settings/muted_users_settings.hbs new file mode 100644 index 0000000000..3eafd9c91c --- /dev/null +++ b/static/templates/settings/muted_users_settings.hbs @@ -0,0 +1,13 @@ +
+ +
+ + + + + + + +
{{t "User" }}{{t "Date muted" }}{{t "Actions" }}
+
+
diff --git a/static/templates/settings_tab.hbs b/static/templates/settings_tab.hbs index eb01383c4c..95c3706839 100644 --- a/static/templates/settings_tab.hbs +++ b/static/templates/settings_tab.hbs @@ -12,4 +12,6 @@ {{> settings/attachments_settings }} {{> settings/muted_topics_settings }} + + {{> settings/muted_users_settings }} diff --git a/templates/zerver/app/settings_overlay.html b/templates/zerver/app/settings_overlay.html index 3f4d0e5cce..9a14eaa28b 100644 --- a/templates/zerver/app/settings_overlay.html +++ b/templates/zerver/app/settings_overlay.html @@ -43,6 +43,12 @@
{{ _('Muted topics') }}
+ {% if development_environment %} +
  • + +
    {{ _('Muted users') }}
    +
  • + {% endif %}