muting ui: Update the muted topics table in settings.

The set_up_muted_topics_ui and templates have been
refactored to use list_render.
This is done to support filtering and sorting of
the muted stream topics.

This also includes the addition of a new Date muted header.
This commit is contained in:
Ryan Rehman 2020-02-05 17:44:24 +05:30 committed by Tim Abbott
parent 6983491a0f
commit 3bc818b9f7
7 changed files with 106 additions and 51 deletions

View File

@ -1,6 +1,9 @@
zrequire('timerender');
zrequire('muting');
zrequire('stream_data');
set_global('i18n', global.stub_i18n);
set_global('XDate', zrequire('XDate', 'xdate'));
set_global('page_params', {});
run_test('edge_cases', () => {
@ -61,27 +64,49 @@ run_test('basics', () => {
run_test('get_and_set_muted_topics', () => {
assert.deepEqual(muting.get_muted_topics(), []);
muting.add_muted_topic(office.stream_id, 'gossip');
muting.add_muted_topic(devel.stream_id, 'java');
muting.add_muted_topic(office.stream_id, 'gossip', 1577836800);
muting.add_muted_topic(devel.stream_id, 'java', 1577836800);
assert.deepEqual(muting.get_muted_topics().sort(), [
[devel.stream_id, 'java'],
[office.stream_id, 'gossip'],
]);
{
date_muted: 1577836800000,
date_muted_str: 'Jan 01',
stream: devel.name,
stream_id: devel.stream_id,
topic: 'java',
},
{
date_muted: 1577836800000,
date_muted_str: 'Jan 01',
stream: office.name,
stream_id: office.stream_id,
topic: 'gossip',
}]);
blueslip.expect('warn', 'Unknown stream in set_muted_topics: BOGUS STREAM');
page_params.muted_topics = [
['social', 'breakfast'],
['design', 'typography'],
['BOGUS STREAM', 'whatever'],
['social', 'breakfast', 1577836800],
['design', 'typography', 1577836800],
['BOGUS STREAM', 'whatever', 1577836800],
];
muting.initialize();
assert.deepEqual(muting.get_muted_topics().sort(), [
[design.stream_id, 'typography'],
[social.stream_id, 'breakfast'],
]);
{
date_muted: 1577836800000,
date_muted_str: 'Jan 01',
stream: social.name,
stream_id: social.stream_id,
topic: 'breakfast',
},
{
date_muted: 1577836800000,
date_muted_str: 'Jan 01',
stream: design.name,
stream_id: design.stream_id,
topic: 'typography',
}]);
});
run_test('case_insensitivity', () => {

View File

@ -1,5 +1,7 @@
set_global('$', global.make_zjquery());
set_global('XDate', zrequire('XDate', 'xdate'));
zrequire('timerender');
zrequire('settings_muting');
zrequire('stream_data');
zrequire('muting');
@ -15,10 +17,17 @@ stream_data.add_sub(frontend);
run_test('settings', () => {
muting.add_muted_topic(frontend.stream_id, 'js');
muting.add_muted_topic(frontend.stream_id, 'js', 1577836800);
let set_up_ui_called = false;
muting_ui.set_up_muted_topics_ui = function (opts) {
assert.deepEqual(opts, [[frontend.stream_id, 'js']]);
assert.deepEqual(opts, [
{
date_muted: 1577836800000,
date_muted_str: 'Jan 01',
stream: frontend.name,
stream_id: frontend.stream_id,
topic: 'js',
}]);
set_up_ui_called = true;
};

View File

@ -1,4 +1,5 @@
zrequire('timerender');
zrequire('muting');
zrequire('people');
zrequire('stream_data');
@ -11,6 +12,9 @@ zrequire('settings_notifications');
const FoldDict = zrequire('fold_dict').FoldDict;
set_global('i18n', global.stub_i18n);
set_global('XDate', zrequire('XDate', 'xdate'));
set_global('page_params', {});
set_global('narrow_state', {});
set_global('current_msg_list', {});
set_global('home_msg_list', {});

View File

@ -2,13 +2,17 @@ const FoldDict = require('./fold_dict').FoldDict;
const muted_topics = new Map();
exports.add_muted_topic = function (stream_id, topic) {
exports.add_muted_topic = function (stream_id, topic, date_muted) {
let sub_dict = muted_topics.get(stream_id);
if (!sub_dict) {
sub_dict = new FoldDict();
muted_topics.set(stream_id, sub_dict);
}
sub_dict.set(topic, true);
let time = date_muted * 1000;
if (!date_muted) {
time = Date.now();
}
sub_dict.set(topic, time);
};
exports.remove_muted_topic = function (stream_id, topic) {
@ -29,8 +33,17 @@ exports.is_topic_muted = function (stream_id, topic) {
exports.get_muted_topics = function () {
const topics = [];
for (const [stream_id, sub_dict] of muted_topics) {
const stream = stream_data.maybe_get_stream_name(stream_id);
for (const topic of sub_dict.keys()) {
topics.push([stream_id, topic]);
const date_muted = sub_dict.get(topic);
const date_muted_str = timerender.render_now(new XDate(date_muted)).time_str;
topics.push({
stream_id: stream_id,
stream: stream,
topic: topic,
date_muted: date_muted,
date_muted_str: date_muted_str,
});
}
}
return topics;
@ -42,6 +55,7 @@ exports.set_muted_topics = function (tuples) {
for (const tuple of tuples) {
const stream_name = tuple[0];
const topic = tuple[1];
const date_muted = tuple[2];
const stream_id = stream_data.get_stream_id(stream_name);
@ -50,7 +64,7 @@ exports.set_muted_topics = function (tuples) {
continue;
}
exports.add_muted_topic(stream_id, topic);
exports.add_muted_topic(stream_id, topic, date_muted);
}
};

View File

@ -68,29 +68,25 @@ exports.update_muted_topics = function (muted_topics) {
};
exports.set_up_muted_topics_ui = function (muted_topics) {
const muted_topics_table = $("#muted_topics_table tbody");
muted_topics_table.empty();
const muted_topics_table = $("#muted_topics_table").expectOne();
const $search_input = $("#muted_topics_search");
for (const tup of muted_topics) {
const stream_id = tup[0];
const topic = tup[1];
const stream = stream_data.maybe_get_stream_name(stream_id);
if (!stream) {
blueslip.warn('Unknown stream_id in set_up_muted_topics_ui: ' + stream_id);
continue;
}
const template_data = {
stream: stream,
stream_id: stream_id,
topic: topic,
};
const row = render_muted_topic_ui_row(template_data);
muted_topics_table.append(row);
}
list_render.create(muted_topics_table, muted_topics, {
name: "muted-topics-list",
modifier: function (muted_topics) {
return render_muted_topic_ui_row({ muted_topics: muted_topics });
},
filter: {
element: $search_input,
predicate: function (item, value) {
return item.topic.toLocaleLowerCase().indexOf(value) >= 0;
},
onupdate: function () {
ui.reset_scrollbar(muted_topics_table.closest(".progressive-table-wrapper"));
},
},
parent_container: $('#muted-topic-settings').expectOne(),
});
};
exports.mute = function (stream_id, topic) {
@ -114,7 +110,6 @@ exports.mute = function (stream_id, topic) {
title_text: i18n.t("Topic muted"),
undo_button_text: i18n.t("Unmute"),
});
exports.set_up_muted_topics_ui(muting.get_muted_topics());
};
exports.unmute = function (stream_id, topic) {
@ -126,7 +121,6 @@ exports.unmute = function (stream_id, topic) {
unread_ui.update_unread_counts();
exports.rerender();
exports.persist_unmute(stream_id, topic);
exports.set_up_muted_topics_ui(muting.get_muted_topics());
feedback_widget.dismiss();
};

View File

@ -1,5 +1,10 @@
<tr data-stream-id="{{stream_id}}" data-topic="{{topic}}">
{{#with muted_topics}}
<tr data-stream-id={{stream_id}} data-stream="{{stream}}" data-topic="{{topic}}" data-date-muted="{{date_muted_str}}">
<td>{{stream}}</td>
<td>{{topic}}</td>
<td><a class="settings-unmute-topic">Unmute</a></td>
<td>{{date_muted_str}}</td>
<td class="actions">
<span><a class="settings-unmute-topic">Unmute</a></span>
</td>
</tr>
{{/with}}

View File

@ -1,10 +1,14 @@
<div id="muted-topic-settings" class="settings-section" data-name="muted-topics">
<table id="muted_topics_table" class="table">
<input id="muted_topics_search" class="search" type="text" placeholder="{{t 'Search muted topics...' }}" aria-label="{{t 'Search muted topics...' }}"/>
<div class="progressive-table-wrapper" data-simplebar data-list-render="muted-topics-list">
<table class="table table-condensed table-striped wrapped-table">
<thead>
<th>{{t "Stream" }}</th>
<th>{{t "Topic" }}</th>
<th data-sort="alphabetic" data-sort-prop="stream">{{t "Stream" }}</th>
<th data-sort="alphabetic" data-sort-prop="topic">{{t "Topic" }}</th>
<th data-sort="numeric" data-sort-prop="date_muted">{{t "Date muted" }}</th>
<th class="actions">{{t "Actions" }}</th>
</thead>
<tbody class="required-text" data-empty="{{t 'You have not muted any topics yet.'}}"></tbody>
<tbody id="muted_topics_table" data-empty="{{t 'You have not muted any topics yet.'}}" data-list-render="muted-topics-list"></tbody>
</table>
</div>
</div>