stream settings: Fix UI feedback on clicking checkbox to subscribe.

Before this change, on clicking a checkbox to toggle subscription to a
stream no UI feedback was shown and users could toggle the checkbox
multiple times to send multiple requests causing bugs. This commit
initializes a spinner on clicking the checkbox, to provide a UI feedback
to the user. This commit also disables the checkbox once a request for
subscription has been sent and re-enables the checkbox only after a
response.

This change has been accomplished by introducing a div to display the
spinner in subscription.hbs. The corresponding styles for the spinner
have been added in subscriptions.scss. The ajaxSubscribe &
ajaxUnsubscribe functions in subs.js have been updated to show & hide
the spinners for the time the request is in process. An additional
parameter, the concerned stream object is passed to these functions(
through the sub_or_unsub function) to get the location where the spinner
is to be displayed. Finally, the checkbox click handler is updated to
support these changes.

The testing for this has been done by adding a wait of 2 secs in
actions.py for the response. This gives sufficient time to test the
working manually. Also, for error cases an error has been sent from
action.py and the behaviour has been manually observed.

Fixes #14481.
This commit is contained in:
Pranav 2020-04-16 18:17:43 +05:30 committed by Tim Abbott
parent cc542a607e
commit 3b71e0dbfb
4 changed files with 72 additions and 6 deletions

View File

@ -634,7 +634,7 @@ exports.initialize = function () {
$("#subscriptions_table").on("click", ".sub_unsub_button", function (e) {
const sub = get_sub_for_target(e.target);
const stream_row = $(this).parent();
subs.sub_or_unsub(sub);
subs.sub_or_unsub(sub, e.currentTarget);
if (!sub.subscribed) {
exports.open_edit_panel_for_row(stream_row);
}

View File

@ -718,10 +718,42 @@ exports.view_stream = function () {
}
};
function ajaxSubscribe(stream, color) {
/* For the given row_object, remove the tick and replace by a spinner. */
function display_subscribe_toggle_spinner(row_object) {
/* Prevent sending multiple requests by removing the button class. */
$(row_object).removeClass("sub_unsub_button");
/* Hide the tick. */
const tick = $(row_object).find("svg");
tick.addClass("hide");
/* Add a spinner to show the request is in process. */
const spinner = $(row_object).find(".sub_unsub_status").expectOne();
spinner.show();
loading.make_indicator(spinner);
}
/* For the given row_object, add the tick and delete the spinner. */
function hide_subscribe_toggle_spinner(row_object) {
/* Re-enable the button to handle requests. */
$(row_object).addClass("sub_unsub_button");
/* Show the tick. */
const tick = $(row_object).find("svg");
tick.removeClass("hide");
/* Destroy the spinner. */
const spinner = $(row_object).find(".sub_unsub_status").expectOne();
loading.destroy_indicator(spinner);
}
function ajaxSubscribe(stream, color, row_object) {
// Subscribe yourself to a single stream.
let true_stream_name;
if (row_object !== undefined) {
display_subscribe_toggle_spinner(row_object);
}
return channel.post({
url: "/json/users/me/subscriptions",
data: {subscriptions: JSON.stringify([{name: stream, color: color}]) },
@ -738,24 +770,41 @@ function ajaxSubscribe(stream, color) {
$(".stream_change_property_info"));
}
// The rest of the work is done via the subscribe event we will get
if (row_object !== undefined) {
hide_subscribe_toggle_spinner(row_object);
}
},
error: function (xhr) {
if (row_object !== undefined) {
hide_subscribe_toggle_spinner(row_object);
}
ui_report.error(i18n.t("Error adding subscription"), xhr,
$(".stream_change_property_info"));
},
});
}
function ajaxUnsubscribe(sub) {
function ajaxUnsubscribe(sub, row_object) {
// TODO: use stream_id when backend supports it
if (row_object !== undefined) {
display_subscribe_toggle_spinner(row_object);
}
return channel.del({
url: "/json/users/me/subscriptions",
data: {subscriptions: JSON.stringify([sub.name]) },
success: function () {
$(".stream_change_property_info").hide();
// The rest of the work is done via the unsubscribe event we will get
if (row_object !== undefined) {
hide_subscribe_toggle_spinner(row_object);
}
},
error: function (xhr) {
if (row_object !== undefined) {
hide_subscribe_toggle_spinner(row_object);
}
ui_report.error(i18n.t("Error removing subscription"), xhr,
$(".stream_change_property_info"));
},
@ -784,11 +833,11 @@ exports.open_create_stream = function () {
};
exports.sub_or_unsub = function (sub) {
exports.sub_or_unsub = function (sub, row_object) {
if (sub.subscribed) {
ajaxUnsubscribe(sub);
ajaxUnsubscribe(sub, row_object);
} else {
ajaxSubscribe(sub.name, sub.color);
ajaxSubscribe(sub.name, sub.color, row_object);
}
};

View File

@ -611,6 +611,22 @@ form#add_new_subscription {
pointer-events: none;
visibility: hidden;
}
.sub_unsub_status {
display: inline-block !important;
height: auto !important;
width: auto !important;
.loading_indicator_spinner {
width: 100%;
height: 100%;
margin: 0;
}
.loading_indicator_spinner svg path {
fill: hsl(178, 100%, 40%);
}
}
}
.checked svg {

View File

@ -6,6 +6,7 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="100%" height="100%" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path d="M448,71.9c-17.3-13.4-41.5-9.3-54.1,9.1L214,344.2l-99.1-107.3c-14.6-16.6-39.1-17.4-54.7-1.8 c-15.6,15.5-16.4,41.6-1.7,58.1c0,0,120.4,133.6,137.7,147c17.3,13.4,41.5,9.3,54.1-9.1l206.3-301.7 C469.2,110.9,465.3,85.2,448,71.9z"/>
</svg>
<div class='sub_unsub_status'></div>
</div>
{{> subscription_setting_icon }}
<div class="sub-info-box">