From 3b71e0dbfb727b75f18d7272860b26515eb05535 Mon Sep 17 00:00:00 2001 From: Pranav Date: Thu, 16 Apr 2020 18:17:43 +0530 Subject: [PATCH] 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. --- static/js/stream_edit.js | 2 +- static/js/subs.js | 59 ++++++++++++++++++++++++++++--- static/styles/subscriptions.scss | 16 +++++++++ static/templates/subscription.hbs | 1 + 4 files changed, 72 insertions(+), 6 deletions(-) diff --git a/static/js/stream_edit.js b/static/js/stream_edit.js index 46dd5cf467..3cffb9a3db 100644 --- a/static/js/stream_edit.js +++ b/static/js/stream_edit.js @@ -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); } diff --git a/static/js/subs.js b/static/js/subs.js index 507fd6d4f7..6a385ff8eb 100644 --- a/static/js/subs.js +++ b/static/js/subs.js @@ -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); } }; diff --git a/static/styles/subscriptions.scss b/static/styles/subscriptions.scss index 1577d89d33..b0a30ac362 100644 --- a/static/styles/subscriptions.scss +++ b/static/styles/subscriptions.scss @@ -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 { diff --git a/static/templates/subscription.hbs b/static/templates/subscription.hbs index bcbd6fa639..f7bcaa0d0b 100644 --- a/static/templates/subscription.hbs +++ b/static/templates/subscription.hbs @@ -6,6 +6,7 @@ +
{{> subscription_setting_icon }}