mirror of https://github.com/zulip/zulip.git
streams: Implement copy-subscribers feature.
In the new stream creation modal, added checkboxes for each stream and a toggle to see or hide the checkboxes. Altered filtering to filter streams and users. Added corresponding casper tests. When a stream is checked/unchecked, it does not affect the state of any user checkbox. This may be visually unclear as users can be added even if their checkboxes are empty. Fixes #2448
This commit is contained in:
parent
e87cc4e622
commit
06615bee00
|
@ -28,20 +28,38 @@ casper.waitForSelector('.sub_unsub_button.checked', function () {
|
||||||
|
|
||||||
casper.then(function () {
|
casper.then(function () {
|
||||||
casper.test.assertExists('#user-checkboxes [data-name="cordelia@zulip.com"]', 'Original user list contains Cordelia');
|
casper.test.assertExists('#user-checkboxes [data-name="cordelia@zulip.com"]', 'Original user list contains Cordelia');
|
||||||
casper.test.assertExists('#user-checkboxes [data-name="hamlet@zulip.com"]', 'Original user list contains King Hamlet');
|
casper.test.assertExists('#user-checkboxes [data-name="othello@zulip.com"]', 'Original user list contains Othello');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
casper.waitForSelector("#copy-from-stream-expand-collapse", function () {
|
||||||
|
casper.click('#copy-from-stream-expand-collapse');
|
||||||
|
});
|
||||||
|
|
||||||
|
casper.waitUntilVisible("#stream-checkboxes", function () {
|
||||||
|
casper.test.assertExists('#stream-checkboxes [data-name="Scotland"]', 'Original stream list contains Scotland');
|
||||||
|
casper.test.assertExists('#stream-checkboxes [data-name="Rome"]', 'Original stream list contains Rome');
|
||||||
|
});
|
||||||
|
|
||||||
casper.waitForSelector("form#stream_creation_form", function () {
|
casper.waitForSelector("form#stream_creation_form", function () {
|
||||||
casper.test.info("Filtering user list with keyword 'cor'");
|
casper.test.info("Filtering with keyword 'ot'");
|
||||||
casper.fill('form#stream_creation_form', {user_list_filter: 'cor'});
|
casper.fill('form#stream_creation_form', {user_list_filter: 'ot'});
|
||||||
});
|
});
|
||||||
casper.waitForSelector(".subscriber-list", function () {
|
casper.waitForSelector(".subscriber-list", function () {
|
||||||
casper.test.assertEquals(casper.visible('#user-checkboxes [data-name="cordelia@zulip.com"]'),
|
casper.test.assertEquals(casper.visible('#user-checkboxes [data-name="cordelia@zulip.com"]'),
|
||||||
true,
|
|
||||||
"Cordelia is visible"
|
|
||||||
);
|
|
||||||
casper.test.assertEquals(casper.visible('#user-checkboxes [data-name="hamlet@zulip.com"]'),
|
|
||||||
false,
|
false,
|
||||||
"King Hamlet is not visible"
|
"Cordelia is not visible"
|
||||||
|
);
|
||||||
|
casper.test.assertEquals(casper.visible('#user-checkboxes [data-name="othello@zulip.com"]'),
|
||||||
|
true,
|
||||||
|
"Othello is visible"
|
||||||
|
);
|
||||||
|
casper.test.assertEquals(casper.visible('#stream-checkboxes [data-name="Scotland"]'),
|
||||||
|
true,
|
||||||
|
"Scotland is visible"
|
||||||
|
);
|
||||||
|
casper.test.assertEquals(casper.visible('#stream-checkboxes [data-name="Rome"]'),
|
||||||
|
false,
|
||||||
|
"Rome is not visible"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
casper.then(function () {
|
casper.then(function () {
|
||||||
|
@ -53,14 +71,25 @@ casper.then(function () {
|
||||||
true,
|
true,
|
||||||
"Cordelia is visible again"
|
"Cordelia is visible again"
|
||||||
);
|
);
|
||||||
casper.test.assertEquals(casper.visible('#user-checkboxes [data-name="hamlet@zulip.com"]'),
|
casper.test.assertEquals(casper.visible('#user-checkboxes [data-name="othello@zulip.com"]'),
|
||||||
true,
|
true,
|
||||||
"King Hamlet is visible again"
|
"Othello is visible again"
|
||||||
|
);
|
||||||
|
casper.test.assertEquals(casper.visible('#stream-checkboxes [data-name="Scotland"]'),
|
||||||
|
true,
|
||||||
|
"Scotland is visible again"
|
||||||
|
);
|
||||||
|
casper.test.assertEquals(casper.visible('#stream-checkboxes [data-name="Rome"]'),
|
||||||
|
true,
|
||||||
|
"Rome is visible again"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
casper.waitForSelector('#stream_creation_form', function () {
|
casper.waitForSelector('#stream_creation_form', function () {
|
||||||
casper.test.assertTextExists('Add New Stream', 'New stream creation panel');
|
casper.test.assertTextExists('Add New Stream', 'New stream creation panel');
|
||||||
casper.fill('form#stream_creation_form', {stream_name: 'Waseemio', stream_description: 'Oimeesaw'});
|
casper.fill('form#stream_creation_form', {stream_name: 'Waseemio', stream_description: 'Oimeesaw'});
|
||||||
|
casper.click('input[value="Scotland"] ~ span');
|
||||||
|
casper.click('input[value="cordelia@zulip.com"] ~ span');
|
||||||
|
casper.click('input[value="othello@zulip.com"] ~ span');
|
||||||
casper.click('form#stream_creation_form button.btn.btn-primary');
|
casper.click('form#stream_creation_form button.btn.btn-primary');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -73,6 +102,10 @@ casper.then(function () {
|
||||||
casper.test.info("User should be subscribed to stream Waseemio");
|
casper.test.info("User should be subscribed to stream Waseemio");
|
||||||
casper.test.assertSelectorHasText('.stream-name', 'Waseemio');
|
casper.test.assertSelectorHasText('.stream-name', 'Waseemio');
|
||||||
casper.test.assertSelectorHasText('.description', 'Oimeesaw');
|
casper.test.assertSelectorHasText('.description', 'Oimeesaw');
|
||||||
|
// Based on the selected checkboxes while creating stream,
|
||||||
|
// 4 users from Scotland are added.
|
||||||
|
// 1 user, Cordelia, is added. Othello (subscribed to Scotland) is not added twice.
|
||||||
|
casper.test.assertSelectorHasText('.subscriber-count-text', '5');
|
||||||
casper.fill('form#add_new_subscription', {stream_name: 'WASeemio'});
|
casper.fill('form#add_new_subscription', {stream_name: 'WASeemio'});
|
||||||
casper.click('#create_stream_button');
|
casper.click('#create_stream_button');
|
||||||
});
|
});
|
||||||
|
|
|
@ -762,7 +762,8 @@ function show_new_stream_modal() {
|
||||||
$("#stream-creation").removeClass("hide");
|
$("#stream-creation").removeClass("hide");
|
||||||
$(".right .settings").hide();
|
$(".right .settings").hide();
|
||||||
$('#people_to_add').html(templates.render('new_stream_users', {
|
$('#people_to_add').html(templates.render('new_stream_users', {
|
||||||
users: people.get_rest_of_realm()
|
users: people.get_rest_of_realm(),
|
||||||
|
streams: stream_data.get_streams_for_settings_page()
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Make the options default to the same each time:
|
// Make the options default to the same each time:
|
||||||
|
@ -864,10 +865,17 @@ $(function () {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
update_announce_stream_state();
|
update_announce_stream_state();
|
||||||
});
|
});
|
||||||
|
$(document).on('click', '#copy-from-stream-expand-collapse', function (e) {
|
||||||
|
$('#stream-checkboxes').toggle();
|
||||||
|
$("#copy-from-stream-expand-collapse .toggle").toggleClass('icon-vector-caret-right icon-vector-caret-down');
|
||||||
|
e.preventDefault();
|
||||||
|
update_announce_stream_state();
|
||||||
|
});
|
||||||
|
|
||||||
// Search People
|
// Search People or Streams
|
||||||
$(document).on('input', '.add-user-list-filter', function (e) {
|
$(document).on('input', '.add-user-list-filter', function (e) {
|
||||||
var users = people.get_rest_of_realm();
|
var users = people.get_rest_of_realm();
|
||||||
|
var streams = stream_data.get_streams_for_settings_page();
|
||||||
|
|
||||||
var user_list = $(".add-user-list-filter");
|
var user_list = $(".add-user-list-filter");
|
||||||
if (user_list === 0) {
|
if (user_list === 0) {
|
||||||
|
@ -877,6 +885,23 @@ $(function () {
|
||||||
var search_terms = search_term.toLowerCase().split(",");
|
var search_terms = search_term.toLowerCase().split(",");
|
||||||
var filtered_users = people.filter_people_by_search_terms(users, search_terms);
|
var filtered_users = people.filter_people_by_search_terms(users, search_terms);
|
||||||
|
|
||||||
|
_.each(streams, function (stream) {
|
||||||
|
var flag = true;
|
||||||
|
|
||||||
|
flag = flag && (function () {
|
||||||
|
var sub_name = stream.name.toLowerCase();
|
||||||
|
var matches_list = search_terms.indexOf(sub_name) > -1;
|
||||||
|
var matches_last_val = sub_name.match(search_terms[search_terms.length - 1]);
|
||||||
|
return matches_list || matches_last_val;
|
||||||
|
}());
|
||||||
|
|
||||||
|
if (flag) {
|
||||||
|
$("label[data-name='" + stream.name + "']").css("display", "block");
|
||||||
|
} else {
|
||||||
|
$("label[data-name='" + stream.name + "']").css("display", "none");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Hide users which aren't in filtered users
|
// Hide users which aren't in filtered users
|
||||||
_.each(users, function (user) {
|
_.each(users, function (user) {
|
||||||
var display_type = filtered_users.hasOwnProperty(user.email)? "block" : "none";
|
var display_type = filtered_users.hasOwnProperty(user.email)? "block" : "none";
|
||||||
|
@ -929,6 +954,33 @@ $(function () {
|
||||||
return $(elem).val();
|
return $(elem).val();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
var checked_streams = _.map(
|
||||||
|
$("#stream_creation_form input:checkbox[name=stream]:checked"),
|
||||||
|
function (elem) {
|
||||||
|
return $(elem).val();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
var checked_stream_emails = [];
|
||||||
|
var stream_emails = [];
|
||||||
|
|
||||||
|
_.each(checked_streams, function (checked_stream) {
|
||||||
|
stream_emails = [];
|
||||||
|
var subscriber_ids = stream_data.get_sub(checked_stream).subscribers.keys();
|
||||||
|
_.each(subscriber_ids, function (subscriber_id) {
|
||||||
|
stream_emails.push(people.get_person_from_user_id(subscriber_id).email);
|
||||||
|
});
|
||||||
|
checked_stream_emails = _.union(checked_stream_emails, stream_emails);
|
||||||
|
});
|
||||||
|
|
||||||
|
// If a stream was checked and the checkboxes are not visible,
|
||||||
|
// don't add checked streams
|
||||||
|
if ($('#stream-checkboxes').css('display') !== 'none') {
|
||||||
|
principals = _.union(principals, checked_stream_emails);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// You are always subscribed to streams you create.
|
// You are always subscribed to streams you create.
|
||||||
principals.push(page_params.email);
|
principals.push(page_params.email);
|
||||||
|
|
||||||
|
|
|
@ -2113,6 +2113,24 @@ div.floating_recipient {
|
||||||
float: none;
|
float: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#stream-checkboxes {
|
||||||
|
margin-top: 10px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#stream-checkboxes .checkbox {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#stream-checkboxes .checkbox input[type=checkbox] {
|
||||||
|
margin: 5px 0px;
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#copy-from-stream-expand-collapse {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.streams_popover .sp-container {
|
.streams_popover .sp-container {
|
||||||
background: white;
|
background: white;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
|
@ -1,7 +1,22 @@
|
||||||
{{! Client-side Mustache template for rendering users in the stream creation modal.}}
|
{{! Client-side Mustache template for rendering users in the stream creation modal.}}
|
||||||
<a href="#" class="subs_set_all_users">{{t "Check all" }}</a> |
|
<a href="#" class="subs_set_all_users">{{t "Check all" }}</a> |
|
||||||
<a href="#" class="subs_unset_all_users">{{t "Uncheck all" }}</a>
|
<a href="#" class="subs_unset_all_users">{{t "Uncheck all" }}</a>
|
||||||
<input class="add-user-list-filter" name="user_list_filter" type="text" placeholder="{{t "Filter users" }}" />
|
<input class="add-user-list-filter" name="user_list_filter" type="text" placeholder="{{t "Filter" }}" />
|
||||||
|
<div id="copy-from-stream-expand-collapse" class="add-user-label">
|
||||||
|
<i class="toggle icon-vector-caret-right"></i>
|
||||||
|
<span class="control-label">
|
||||||
|
{{t "Copy from Stream" }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div id="stream-checkboxes">
|
||||||
|
{{#each streams}}
|
||||||
|
<label class="checkbox add-user-label" data-name="{{this.name}}">
|
||||||
|
<input type="checkbox" name="stream" value="{{this.name}}" />
|
||||||
|
<span></span>
|
||||||
|
{{this.name}} ( <i class="icon-vector-user"></i> {{this.subscriber_count}})
|
||||||
|
</label>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
<div id="user-checkboxes">
|
<div id="user-checkboxes">
|
||||||
{{#each users}}
|
{{#each users}}
|
||||||
<label class="checkbox add-user-label" data-name="{{this.email}}">
|
<label class="checkbox add-user-label" data-name="{{this.email}}">
|
||||||
|
|
Loading…
Reference in New Issue