mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-03 21:43:21 +00:00 
			
		
		
		
	stream_filtering: Filter streams on subscriptions page.
Filter behaves similarly to filter in left sidebar, see PR #684. Added stream input field to the stream creation modal along with other settings, for clarity. Fixes #455, #563.
This commit is contained in:
		@@ -21,11 +21,12 @@ casper.then(function () {
 | 
			
		||||
 | 
			
		||||
casper.waitForSelector('.sub_unsub_button.subscribed-button', function () {
 | 
			
		||||
    casper.test.assertTextExists('Subscribed', 'Initial subscriptions loaded');
 | 
			
		||||
    casper.fill('form#add_new_subscription', {stream_name: 'Waseemio'});
 | 
			
		||||
    casper.click('form#add_new_subscription input.btn');
 | 
			
		||||
});
 | 
			
		||||
casper.waitForText('Waseemio', function () {
 | 
			
		||||
    casper.test.assertTextExists('Create stream Waseemio', 'Modal for specifying new stream users');
 | 
			
		||||
casper.waitForSelector('#create_stream_button', function () {
 | 
			
		||||
     casper.test.assertTextExists('Create stream', 'Modal for specifying new stream users');
 | 
			
		||||
     casper.fill('form#stream_creation_form', {stream_name: 'Waseemio'});
 | 
			
		||||
     casper.click('form#stream_creation_form button.btn.btn-primary');
 | 
			
		||||
});
 | 
			
		||||
casper.then(function () {
 | 
			
		||||
    casper.test.assertExists('#user-checkboxes [data-name="cordelia@zulip.com"]', 'Original user list contains Cordelia');
 | 
			
		||||
@@ -59,16 +60,11 @@ casper.then(function () {
 | 
			
		||||
                             "King Hamlet is visible again"
 | 
			
		||||
    );
 | 
			
		||||
});
 | 
			
		||||
casper.then(function () {
 | 
			
		||||
    casper.test.assertTextExists('Create stream Waseemio', 'Create a new stream');
 | 
			
		||||
    casper.click('form#stream_creation_form button.btn.btn-primary');
 | 
			
		||||
});
 | 
			
		||||
casper.waitFor(function () {
 | 
			
		||||
    return casper.evaluate(function () {
 | 
			
		||||
        return $('.subscription_name').is(':contains("Waseemio")');
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
casper.then(function () {
 | 
			
		||||
    casper.test.assertSelectorHasText('.subscription_name', 'Waseemio', 'Subscribing to a stream');
 | 
			
		||||
    casper.fill('form#add_new_subscription', {stream_name: 'WASeemio'});
 | 
			
		||||
@@ -79,8 +75,32 @@ casper.waitForText('Already subscribed', function () {
 | 
			
		||||
    casper.fill('form#add_new_subscription', {stream_name: '  '});
 | 
			
		||||
    casper.click('form#add_new_subscription input.btn');
 | 
			
		||||
});
 | 
			
		||||
casper.waitForText('Error adding subscription', function () {
 | 
			
		||||
    casper.test.assertTextExists('Error adding subscription', "Can't subscribe to an empty stream name");
 | 
			
		||||
casper.waitForText('Create stream', function () {
 | 
			
		||||
    casper.test.assertTextExists('Create stream', 'Modal for specifying new stream users');
 | 
			
		||||
    casper.fill('form#stream_creation_form', {stream_name: '  '});
 | 
			
		||||
    casper.click('form#stream_creation_form button.btn.btn-primary');
 | 
			
		||||
});
 | 
			
		||||
casper.waitForText('Error creating stream', function () {
 | 
			
		||||
    casper.test.assertTextExists('Invalid stream name', "Can't create a stream without a name");
 | 
			
		||||
});
 | 
			
		||||
casper.then(function () {
 | 
			
		||||
    casper.test.info('Streams should be filtered when typing in the create box');
 | 
			
		||||
});
 | 
			
		||||
casper.then(function () {
 | 
			
		||||
    casper.test.assertSelectorHasText('.subscription_row .subscription_name', 'Verona', 'Verona stream exists before filtering');
 | 
			
		||||
    casper.test.assertSelectorDoesntHaveText('.subscription_row.notdisplayed .subscription_name', 'Verona', 'Verona stream shown before filtering');
 | 
			
		||||
});
 | 
			
		||||
casper.then(function () {
 | 
			
		||||
    casper.fill('form#add_new_subscription', {stream_name: 'was'});
 | 
			
		||||
    casper.evaluate(function () {
 | 
			
		||||
      $('#add_new_subscription input[type="text"]').expectOne()
 | 
			
		||||
        .trigger($.Event('input'));
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
casper.then(function () {
 | 
			
		||||
    casper.test.assertSelectorHasText('.subscription_row.notdisplayed .subscription_name', 'Verona', 'Verona stream not shown after filtering');
 | 
			
		||||
    casper.test.assertSelectorHasText('.subscription_row .subscription_name', 'Waseemio', 'Waseemio stream exists after filtering');
 | 
			
		||||
    casper.test.assertSelectorDoesntHaveText('.subscription_row.notdisplayed .subscription_name', 'Waseemio', 'Waseemio stream shown after filtering');
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
common.then_log_out();
 | 
			
		||||
 
 | 
			
		||||
@@ -52,7 +52,7 @@ exports.initialize = function () {
 | 
			
		||||
    // link (in the gear menu), then focus the new stream textbox.
 | 
			
		||||
    subs_link.on('click', function (e) {
 | 
			
		||||
        $(document).one('subs_page_loaded.zulip', function (e) {
 | 
			
		||||
            $('#create_stream_name').focus().select();
 | 
			
		||||
            $('#create_or_filter_stream_row input[type="text"]').focus().select();
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -266,7 +266,7 @@ function add_email_hint(row, email_address_hint_content) {
 | 
			
		||||
function add_sub_to_table(sub) {
 | 
			
		||||
    sub = add_admin_options(sub);
 | 
			
		||||
    var html = templates.render('subscription', sub);
 | 
			
		||||
    $('#create_stream_row').after(html);
 | 
			
		||||
    $('#create_or_filter_stream_row').after(html);
 | 
			
		||||
    settings_for_sub(sub).collapse('show');
 | 
			
		||||
    var email_address_hint_content = templates.render('email_address_hint', { page_params: page_params });
 | 
			
		||||
    add_email_hint(sub, email_address_hint_content);
 | 
			
		||||
@@ -437,6 +437,54 @@ function populate_subscriptions(subs, subscribed) {
 | 
			
		||||
    return sub_rows;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
exports.filter_table = function (query) {
 | 
			
		||||
    var sub_name_elements = $('#subscriptions_table .subscription_name');
 | 
			
		||||
 | 
			
		||||
    if (query === '') {
 | 
			
		||||
        _.each(sub_name_elements, function (sub_name_elem) {
 | 
			
		||||
            $(sub_name_elem).parents('.subscription_row').removeClass("notdisplayed");
 | 
			
		||||
        });
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    var search_terms = query.toLowerCase().split(",");
 | 
			
		||||
    search_terms = _.map(search_terms, function (s) {
 | 
			
		||||
        return s.trim();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    _.each(sub_name_elements, function (sub_name_elem) {
 | 
			
		||||
        var sub_name = $(sub_name_elem).text();
 | 
			
		||||
        var matches = _.any(search_terms, function (search_term) {
 | 
			
		||||
            var lower_sub_name = sub_name.toLowerCase();
 | 
			
		||||
            var idx = lower_sub_name.indexOf(search_term);
 | 
			
		||||
            if (idx === 0) {
 | 
			
		||||
                // matched at beginning of the string
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
            // we know now that idx === -1 or idx > 0
 | 
			
		||||
            if (idx !== -1 && lower_sub_name.charAt(idx - 1) === ' ') {
 | 
			
		||||
                // matched with a space immediately preceding
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        if (matches) {
 | 
			
		||||
            $(sub_name_elem).parents('.subscription_row').removeClass("notdisplayed");
 | 
			
		||||
        } else {
 | 
			
		||||
            $(sub_name_elem).parents('.subscription_row').addClass("notdisplayed");
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function actually_filter_streams() {
 | 
			
		||||
    var search_box = $("#create_or_filter_stream_row input[type='text']");
 | 
			
		||||
    var query = search_box.expectOne().val().trim();
 | 
			
		||||
    exports.filter_table(query);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var filter_streams = _.throttle(actually_filter_streams, 50);
 | 
			
		||||
 | 
			
		||||
exports.setup_page = function () {
 | 
			
		||||
    loading.make_indicator($('#subs_page_loading_indicator'));
 | 
			
		||||
 | 
			
		||||
@@ -483,9 +531,11 @@ exports.setup_page = function () {
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        $('#subscriptions_table').empty();
 | 
			
		||||
 | 
			
		||||
        var template_data = {
 | 
			
		||||
            can_create_streams: page_params.can_create_streams,
 | 
			
		||||
            subscriptions: sub_rows
 | 
			
		||||
            subscriptions: sub_rows,
 | 
			
		||||
            hide_all_streams: !should_list_all_streams()
 | 
			
		||||
        };
 | 
			
		||||
        var rendered = templates.render('subscription_table_body', template_data);
 | 
			
		||||
        $('#subscriptions_table').append(rendered);
 | 
			
		||||
@@ -496,6 +546,7 @@ exports.setup_page = function () {
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        loading.destroy_indicator($('#subs_page_loading_indicator'));
 | 
			
		||||
        $("#create_or_filter_stream_row input[type='text']").on("input", filter_streams);
 | 
			
		||||
        $(document).trigger($.Event('subs_page_loaded.zulip'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -575,6 +626,7 @@ function ajaxSubscribe(stream) {
 | 
			
		||||
        data: {"subscriptions": JSON.stringify([{"name": stream}]) },
 | 
			
		||||
        success: function (resp, statusText, xhr, form) {
 | 
			
		||||
            $("#create_stream_name").val("");
 | 
			
		||||
            exports.filter_table("");
 | 
			
		||||
 | 
			
		||||
            var res = JSON.parse(xhr.responseText);
 | 
			
		||||
            if (!$.isEmptyObject(res.already_subscribed)) {
 | 
			
		||||
@@ -608,6 +660,10 @@ function ajaxUnsubscribe(stream) {
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function hide_new_stream_modal() {
 | 
			
		||||
    $('#stream-creation').modal("hide");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function ajaxSubscribeForCreation(stream, principals, invite_only, announce) {
 | 
			
		||||
    // Subscribe yourself and possible other people to a new stream.
 | 
			
		||||
    return channel.post({
 | 
			
		||||
@@ -620,13 +676,13 @@ function ajaxSubscribeForCreation(stream, principals, invite_only, announce) {
 | 
			
		||||
        success: function (data) {
 | 
			
		||||
            $("#create_stream_name").val("");
 | 
			
		||||
            $("#subscriptions-status").hide();
 | 
			
		||||
            $('#stream-creation').modal("hide");
 | 
			
		||||
            hide_new_stream_modal();
 | 
			
		||||
            // The rest of the work is done via the subscribe event we will get
 | 
			
		||||
        },
 | 
			
		||||
        error: function (xhr) {
 | 
			
		||||
            ui.report_error(i18n.t("Error creating stream"), xhr,
 | 
			
		||||
                            $("#subscriptions-status"), 'subscriptions-status');
 | 
			
		||||
            $('#stream-creation').modal("hide");
 | 
			
		||||
            hide_new_stream_modal();
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
@@ -718,14 +774,14 @@ $(function () {
 | 
			
		||||
        e.preventDefault();
 | 
			
		||||
 | 
			
		||||
        if (!should_list_all_streams()) {
 | 
			
		||||
            ajaxSubscribe($("#create_stream_name").val());
 | 
			
		||||
            ajaxSubscribe($("#search_stream_name").val());
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var stream = $.trim($("#create_stream_name").val());
 | 
			
		||||
        var stream = $.trim($("#search_stream_name").val());
 | 
			
		||||
        var stream_status = compose.check_stream_existence(stream);
 | 
			
		||||
        if (stream_status === "does-not-exist") {
 | 
			
		||||
            $("#stream_name").text(stream);
 | 
			
		||||
        if (stream_status === "does-not-exist" || !stream) {
 | 
			
		||||
            $('#create_stream_name').val(stream);
 | 
			
		||||
            show_new_stream_modal();
 | 
			
		||||
        } else {
 | 
			
		||||
            ajaxSubscribe(stream);
 | 
			
		||||
 
 | 
			
		||||
@@ -2645,7 +2645,11 @@ div.floating_recipient {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#add_new_subscription {
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    text-align: left;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#create_or_filter_stream_row > .subscription_table_elem {
 | 
			
		||||
    text-align: left;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#subscriptions-status {
 | 
			
		||||
@@ -2917,21 +2921,28 @@ button.topic_edit_cancel {
 | 
			
		||||
    padding: 0 15px 0 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#create_stream_row td {
 | 
			
		||||
#create_or_filter_stream_row td {
 | 
			
		||||
    background-color: #f3f3f3;
 | 
			
		||||
    border-color: #BBB;
 | 
			
		||||
    border-bottom: 1px solid #BBB;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#create_stream_name {
 | 
			
		||||
#create_or_filter_stream_row input[type="text"] {
 | 
			
		||||
    width: 220px;
 | 
			
		||||
    margin-top: 10px;
 | 
			
		||||
    margin: 5px 0 20px 38px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
form#add_new_subscription {
 | 
			
		||||
    display: inline;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#create_stream_button {
 | 
			
		||||
    min-width: 140px;
 | 
			
		||||
    margin-left: 15px;
 | 
			
		||||
    margin-top: 10px;
 | 
			
		||||
    float: right;
 | 
			
		||||
    margin-top: 9px;
 | 
			
		||||
    /* margin-right: 38px will align with .sub_unsub_button
 | 
			
		||||
       10px will align with the right edge of #subscriptions_table */
 | 
			
		||||
    margin-right: 38px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sub_settings_title {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,15 +1,15 @@
 | 
			
		||||
{{#if can_create_streams}}
 | 
			
		||||
  <div id="create_stream_row">
 | 
			
		||||
      <div class="subscription_table_elem">
 | 
			
		||||
        <form id="add_new_subscription" class="form-inline" action="">
 | 
			
		||||
          <input type="text" name="stream_name" id="create_stream_name"
 | 
			
		||||
                 placeholder="{{t 'Stream name' }}" value="" />
 | 
			
		||||
          <input type="submit" class="btn btn-primary"
 | 
			
		||||
                 id="create_stream_button" value="{{t 'Create new stream' }}" />
 | 
			
		||||
        </form>
 | 
			
		||||
      </div>
 | 
			
		||||
  </div>
 | 
			
		||||
{{/if}}
 | 
			
		||||
<div id="create_or_filter_stream_row">
 | 
			
		||||
    <div class="subscription_table_elem">
 | 
			
		||||
      <form id="add_new_subscription" class="form-inline" action="">
 | 
			
		||||
          <input type="text" name="stream_name" id="search_stream_name"
 | 
			
		||||
            placeholder="{{t 'Filter by stream name' }}" value="" autocomplete="off" />
 | 
			
		||||
          {{#if can_create_streams}}
 | 
			
		||||
              <input type="submit" class="btn btn-primary"
 | 
			
		||||
                id="create_stream_button" value="{{t 'Create new stream' }}" />
 | 
			
		||||
          {{/if}}
 | 
			
		||||
      </form>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
{{#each subscriptions}}
 | 
			
		||||
{{partial "subscription"}}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,10 +2,15 @@
 | 
			
		||||
     aria-labelledby="stream-creation-label" aria-hidden="true">
 | 
			
		||||
  <div class="modal-header">
 | 
			
		||||
    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
 | 
			
		||||
    <h3 id="stream-creation-label">{% trans %}Create stream{% endtrans %} <span id="stream_name"></span></h3>
 | 
			
		||||
    <h3 id="stream-creation-label">{% trans %}Create stream{% endtrans %}</h3>
 | 
			
		||||
  </div>
 | 
			
		||||
  <form id="stream_creation_form" class="form-inline">
 | 
			
		||||
      <div class="modal-body">
 | 
			
		||||
          <div>
 | 
			
		||||
            <b>{% trans %}Stream name{% endtrans %}</b><br />
 | 
			
		||||
            <input type="text" name="stream_name" id="create_stream_name"
 | 
			
		||||
                 placeholder="{{ _('Stream name') }}" value="" autocomplete="off" />
 | 
			
		||||
          </div>
 | 
			
		||||
          <div id="make-invite-only">
 | 
			
		||||
            <b>{% trans %}Stream accessibility{% endtrans %}</b><br />
 | 
			
		||||
            <label class="radio">
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user