[Kimchi-devel] [PATCH] Issue#349: Software Update Grid Keeps Loading when Error Returns

Hongliang Wang hlwang at linux.vnet.ibm.com
Mon Mar 24 03:09:11 UTC 2014


On 03/22/2014 03:39 AM, Aline Manera wrote:
>
> Some comments:
>
>
>
> Which operation failed?
> I think we need to provide a detailed message
>
> For example:
>
> "An error occurs while checking for packages update."
ACK. "Operation failed." is confused because user doesn't know what 
operation means. Will replace it with your suggestion text.
>
> The "Retry" button should be in the footer or be a link instead a button
    For pop-up window or dialog, we put the button in the footer, just 
as what we do in create VM window, edit VM window, etc. Though in this 
case, I still suggest keep the button be here. It's user-friendly to put 
the button after the message so the user will be able to take action 
immediately. It's consistent with grid design: toolbar (which contains 
action buttons) is above data or message.

And the button is intentionally here, rather than a link.
Be aware of that: button is for "*action*", while link is for 
"*redirection*", and sometimes we can choose either of them for button 
link or link button cases.
   1) For example, when we want to switch tabs, the tab pages are listed 
as links like "Guests", "Templates', "Network"; we can't use buttons here.
   2) For another example, when we create a VM with some properties 
(which are general organized as <form> <field>s and put in a <form> 
element), we should use a <button> to trigger the "create" action 
instead of a link (<a href="">).
   3) And the 3rd example, log-in/log-out buttons. Because log in or log 
out action often goes with a redirection: log-in will cause a 
redirection to main page, and log-out will cause a redirection to log-in 
page. So in the case, either button or link is OK.

   For our case, it's for "list software" so no redirection is here. 
Only button can be used here.
>
>
> On 03/21/2014 06:48 AM, Hongliang Wang wrote:
>> Software update grid keeps loading on UI when server returns 500 error.
>> Instead, we shall remove the loading UI and add a message UI to let the
>> user know something is wrong, as well as add a button to allow the user
>> retry.
>>
>> Signed-off-by: Hongliang Wang<hlwang at linux.vnet.ibm.com>
>> ---
>>   ui/css/theme-default/grid.css | 20 +++++++++++++
>>   ui/js/src/kimchi.api.js       |  4 +--
>>   ui/js/src/kimchi.grid.js      | 66 +++++++++++++++++++++++++++++++++----------
>>   ui/js/src/kimchi.host.js      | 11 +++++++-
>>   ui/pages/i18n.html.tmpl       |  5 ++++
>>   5 files changed, 87 insertions(+), 19 deletions(-)
>>
>> diff --git a/ui/css/theme-default/grid.css b/ui/css/theme-default/grid.css
>> index 44ae614..684dd7b 100644
>> --- a/ui/css/theme-default/grid.css
>> +++ b/ui/css/theme-default/grid.css
>> @@ -239,3 +239,23 @@
>>       height: 48px;
>>       width: 49px;
>>   }
>> +
>> +.grid-message {
>> +    background: white;
>> +    box-sizing: border-box;
>> +    bottom: 0;
>> +    left: 0;
>> +    overflow: auto;
>> +    padding: .2em .5em;
>> +    position: absolute;
>> +    right: 0;
>> +    z-index: 5;
>> +}
>> +
>> +.grid-message-text {
>> +    line-height: 25px;
>> +}
>> +
>> +.retry-button {
>> +    margin: 0 1em;
>> +}
>> diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js
>> index 4310435..11f83df 100644
>> --- a/ui/js/src/kimchi.api.js
>> +++ b/ui/js/src/kimchi.api.js
>> @@ -838,10 +838,8 @@ var kimchi = {
>>                   }, 200);
>>                   break;
>>               case 'finished':
>> -                suc(result);
>> -                break;
>>               case 'failed':
>> -                err(result);
>> +                suc(result);
>>                   break;
>>               default:
>>                   break;
>> diff --git a/ui/js/src/kimchi.grid.js b/ui/js/src/kimchi.grid.js
>> index 540f1ba..f35228d 100644
>> --- a/ui/js/src/kimchi.grid.js
>> +++ b/ui/js/src/kimchi.grid.js
>> @@ -62,6 +62,18 @@ kimchi.widget.Grid = function(params) {
>>                   '</div>',
>>               '</div>',
>>           '</div>',
>> +        '<div class="grid-message hidden">',
>> +          '<div class="grid-message-text">',
>> +            i18n['KCHGRD6002M'],
>> +            '<button class="retry-button btn-small">',
>> +              i18n['KCHGRD6003M'],
>> +            '</button>',
>> +          '</div>',
>> +          '<div class="detailed-title">',
>> +            i18n['KCHGRD6004M'],
>> +          '</div>',
>> +          '<div class="detailed-text"></div>',
>> +        '</div>',
>>         '</div>'
>>       ];
>>
>> @@ -161,6 +173,9 @@ kimchi.widget.Grid = function(params) {
>>       var maskNode = $('.grid-mask', gridNode);
>>       maskNode.css('top', captionHeight + 'px');
>>
>> +    var messageNode = $('.grid-message', gridNode);
>> +    messageNode.css('top', captionHeight + 'px');
>> +
>>       var fillBody = function(container, fields, data) {
>>           var tbody = ($('tbody', container).length && $('tbody', container))
>>               || $('<tbody></tbody>').appendTo(container);
>> @@ -384,28 +399,49 @@ kimchi.widget.Grid = function(params) {
>>       $('body').on('mousemove', positionResizer);
>>       $('body').on('mouseup', endResizing);
>>
>> +    this.showMessage = function(msg) {
>> +        $('.detailed-text', messageNode).text(msg);
>> +        $(messageNode).removeClass('hidden');
>> +    };
>> +
>> +    this.hideMessage = function() {
>> +        $(messageNode).addClass('hidden');
>> +    };
>> +
>>       this.destroy = function() {
>>           $('body').off('mousemove', positionResizer);
>>           $('body').off('mouseup', endResizing);
>>       };
>>
>>       var data = params['data'];
>> -    if(!data) {
>> -        return;
>> -    }
>> +    var self = this;
>> +    var reload = function() {
>> +        if(!data) {
>> +            return;
>> +        }
>>
>> -    if($.isArray(data)) {
>> -        this.setData(data);
>> -        return;
>> -    }
>> +        $(messageNode).addClass('hidden');
>>
>> -    if($.isFunction(data)) {
>> -        var self = this;
>> -        var loadData = data;
>> -        maskNode.removeClass('hidden');
>> -        loadData(function(data) {
>> +        if($.isArray(data)) {
>>               self.setData(data);
>> -            maskNode.addClass('hidden');
>> -        });
>> -    }
>> +            return;
>> +        }
>> +
>> +        if($.isFunction(data)) {
>> +            var loadData = data;
>> +            maskNode.removeClass('hidden');
>> +            loadData(function(data) {
>> +                self.setData(data);
>> +                maskNode.addClass('hidden');
>> +            });
>> +        }
>> +    };
>> +
>> +    var reloadButton = $('.retry-button', gridNode);
>> +    $(reloadButton).on('click', function(event) {
>> +        reload();
>> +    });
>> +
>> +    this.reload = reload;
>> +    reload();
>>   };
>> diff --git a/ui/js/src/kimchi.host.js b/ui/js/src/kimchi.host.js
>> index 6e4678f..2990cdd 100644
>> --- a/ui/js/src/kimchi.host.js
>> +++ b/ui/js/src/kimchi.host.js
>> @@ -57,7 +57,9 @@ kimchi.host_main = function() {
>>                           kimchi.topic('kimchi/softwareUpdated').publish({
>>                               result: result
>>                           });
>> -                    }, function(result) {
>> +                    }, function(error) {
>> +                        var message = error && error['responseJSON'] && error['responseJSON']['reason'];
>> +                        kimchi.message.error(message || i18n['KCHUPD6009M']);
>>                           $(updateButton).text(i18n['KCHUPD6006M']).prop('disabled', false);
>>                       }, reloadProgressArea);
>>                   }
>> @@ -100,6 +102,13 @@ kimchi.host_main = function() {
>>
>>               var updateButton = $('#' + softwareUpdatesGridID + '-update-button');
>>               $(updateButton).prop('disabled', softwareUpdates.length === 0);
>> +        }, function(error) {
>> +            var message = error && error['responseJSON'] && error['responseJSON']['reason'];
>> +            if($.isFunction(gridCallback)) {
>> +                gridCallback([]);
>> +            }
>> +            softwareUpdatesGrid &&
>> +                softwareUpdatesGrid.showMessage(message || i18n['KCHUPD6008M']);
>>           });
>>       };
>>
>> diff --git a/ui/pages/i18n.html.tmpl b/ui/pages/i18n.html.tmpl
>> index 2f47e50..362cde2 100644
>> --- a/ui/pages/i18n.html.tmpl
>> +++ b/ui/pages/i18n.html.tmpl
>> @@ -60,6 +60,9 @@ var i18n = {
>>       'KCHAPI6006M': "$_("Warning")",
>>
>>       'KCHGRD6001M': "$_("Loading...")",
>> +    'KCHGRD6002M': "$_("Operation failed.")",
>> +    'KCHGRD6003M': "$_("Retry")",
>> +    'KCHGRD6004M': "$_("Detailed message:")",
>>
>>       'KCHTMPL6001W': "$_("No iso found")",
>>
>> @@ -87,6 +90,8 @@ var i18n = {
>>       'KCHUPD6005M': "$_("Repository")",
>>       'KCHUPD6006M': "$_("Update All")",
>>       'KCHUPD6007M': "$_("Updating...")",
>> +    'KCHUPD6008M': "$_("Failed to retrieve updates.")",
>> +    'KCHUPD6009M': "$_("Failed to update package(s).")",
>>
>>
>>       'KCHDR6001M': "$_("Debug report will be removed permanently and can't be recovered. Do you want to continue?")",
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ovirt.org/pipermail/kimchi-devel/attachments/20140324/131f488e/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: image/jpeg
Size: 18618 bytes
Desc: not available
URL: <http://lists.ovirt.org/pipermail/kimchi-devel/attachments/20140324/131f488e/attachment.jpe>


More information about the Kimchi-devel mailing list