[Kimchi-devel] [PATCH v5] UI: Software Update Support

Hongliang Wang hlwang at linux.vnet.ibm.com
Wed Mar 5 09:29:22 UTC 2014


On 03/05/2014 07:11 AM, Adam King wrote:
> On 03/04/2014 01:18 AM, Hongliang Wang wrote:
>> Added UI support for software updating. The Host Tab will initially
>> list available updates to user if there are any; or we will disable
>> "Update All" Button if no updates available.
>>
>>    Please apply following patch first:
>>    * [PATCH] [UI] Grid Widget - Enable/Disable Row Selection
>>
>> v4 -> v5:
>>    5a) Disable row selection in software update grid
>>        (Thanks to Royce's comment)
>>
>> v3 -> v4:
>>    4a) Added the last update output
>>        (Thanks to Aline's comment)
>>    4b) Disabled horizontal resize function of output textarea
>>        (Thanks to Aline's comment)
>>    4c) Added "Update Progress" label to the output textarea
>>        (Thanks to Aline's comment)
>>    4d) Added refreshing the software grid after updating is finished
>>        (Thanks to Aline's comment)
>>    4e) Added software updates grid cleanup when host tab is unloaded
>>
>> v2 -> v3:
>>    3a) Fixed "Update All" Button always being disabled issue
>>        (Thanks to Paulo and Aline's comment)
>>    3b) Updated REST API calling according to back-end change
>>    3c) Added in-progress message when system is being updated
>>        (Thanks to Aline's comment)
>>
>> v1 -> v2:
>>    2a) Fixed "Update All" Button always being disabled issue
>>        (Thanks to Paulo Ricardo Paz Vital's comment)
>>
>> Signed-off-by: Hongliang Wang <hlwang at linux.vnet.ibm.com>
>> ---
>>   ui/css/theme-default/host.css | 29 ++++++++++++++
>>   ui/js/src/kimchi.api.js       | 53 ++++++++++++++++++++++++++
>>   ui/js/src/kimchi.host.js      | 89 
>> +++++++++++++++++++++++++++++++++++++++++++
>>   ui/pages/i18n.html.tmpl       | 10 +++++
>>   ui/pages/tabs/host.html.tmpl  | 17 +++++++++
>>   5 files changed, 198 insertions(+)
>>
>> diff --git a/ui/css/theme-default/host.css 
>> b/ui/css/theme-default/host.css
>> index 470ed1b..0f8b941 100644
>> --- a/ui/css/theme-default/host.css
>> +++ b/ui/css/theme-default/host.css
>> @@ -224,3 +224,32 @@
>>       width: 300px;
>>   }
>>   /* End of Debug Report */
>> +
>> +/* Software Updates */
>> +.host-panel #software-updates-grid {
>> +    border-color: #ddd;
>> +    height: 300px;
>> +    width: 850px;
>> +}
>> +
>> +.software-update-id {
>> +    width: 30px;
>> +}
>> +
>> +.software-update-name,
>> +.software-update-repos {
>> +    width: 220px;
>> +}
>> +
>> +.software-update-version,
>> +.software-update-arch {
>> +    width: 190px;
>> +}
>> +
>> +.host-panel #software-updates-progress-textarea {
>> +    border: 1px solid #ddd;
>> +    height: 100px;
>> +    resize: vertical;
>> +    width: 846px;
>> +}
>> +/* End of Software Updates */
>
> Are these styles any different that the styles we use on other grids?
> Can we use a common set of styles so that the different grids maintain 
> consistent styles?
I believe there are redundant style rules besides rules for grids. We 
need a cleanup to do that. Maybe an item in next release? For this 
patch, I'll check the rules and find reusable rules.
>
>> diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js
>> index fdd9cfc..beaf314 100644
>> --- a/ui/js/src/kimchi.api.js
>> +++ b/ui/js/src/kimchi.api.js
>> @@ -727,5 +727,58 @@ var kimchi = {
>>               success : suc,
>>               error : err
>>           });
>> +    },
>> +
>> +    listSoftwareUpdates : function(suc, err) {
>> +        kimchi.requestJSON({
>> +            url : kimchi.url + 'host/packagesupdate',
>> +            type : 'GET',
>> +            contentType : 'application/json',
>> +            dataType : 'json',
>> +            resend: true,
>> +            success : suc,
>> +            error : err
>> +        });
>> +    },
>> +
>> +    updateSoftwares : function(suc, err, progress) {
>
> Should be updateSoftware
> Its like sheep. The plural of software is software.
ACK. I was using it as short for software packages :-)
>> +        var taskID = -1;
>> +        var onResponse = function(data) {
>> +            taskID = data['id'];
>> +            trackTask();
>> +        };
>> +
>> +        var trackTask = function() {
>> +            kimchi.getTask(taskID, onTaskResponse, err);
>> +        };
>> +
>> +        var onTaskResponse = function(result) {
>> +            var taskStatus = result['status'];
>> +            switch(taskStatus) {
>> +            case 'running':
>> +                progress && progress(result);
>> +                setTimeout(function() {
>> +                    trackTask();
>> +                }, 200);
>> +                break;
>> +            case 'finished':
>> +                suc(result);
>> +                break;
>> +            case 'failed':
>> +                err(result);
>> +                break;
>> +            default:
>> +                break;
>> +            }
>> +        };
>> +
>> +        kimchi.requestJSON({
>> +            url : kimchi.url + 'host/swupdate',
>> +            type : "POST",
>> +            contentType : "application/json",
>> +            dataType : "json",
>> +            success : onResponse,
>> +            error : err
>> +        });
>>       }
>>   };
>> diff --git a/ui/js/src/kimchi.host.js b/ui/js/src/kimchi.host.js
>> index 7974054..e146a75 100644
>> --- a/ui/js/src/kimchi.host.js
>> +++ b/ui/js/src/kimchi.host.js
>> @@ -133,6 +133,88 @@ kimchi.host_main = function() {
>>           });
>>       };
>>
>> +    var softwareUpdatesGridID = 'software-updates-grid';
> I'd just burn this in. The indirection isn't really saving anything, 
> but will make it harder to search for some of the computed IDs
OK. I'll check it. If it can be reused more than 3 times, I'll keep it; 
or I'll burn it in. It's usually used when there are several references 
to avoid hand typing errors.
>> +    var softwareUpdatesGrid = null;
>> +    var progressAreaID = 'software-updates-progress-textarea';
>> +    var reloadProgressArea = function(result) {
>> +        var progressArea = $('#' + progressAreaID)[0];
>> +        $(progressArea).text(result['message']);
>> +        var scrollTop = $(progressArea).prop('scrollHeight');
>> +        $(progressArea).prop('scrollTop', scrollTop);
>> +    };
>> +
>> +    var initSoftwareUpdatesGrid = function(softwareUpdates) {
>> +        softwareUpdatesGrid = new kimchi.widget.Grid({
>> +            container: 'software-updates-grid-container',
>> +            id: softwareUpdatesGridID,
>> +            title: i18n['KCHUPD6001M'],
>> +            rowSelection: 'disabled',
>> +            toolbarButtons: [{
>> +                id: softwareUpdatesGridID + '-update-button',
>> +                label: i18n['KCHUPD6006M'],
>> +                disabled: true,
>> +                onClick: function(event) {
>> +                    var updateButton = $(this);
>> +                    var progressArea = $('#' + progressAreaID)[0];
>> + $('#software-updates-progress-container').removeClass('hidden');
>> +                    $(progressArea).text('');
>> +                    !kimchi.isElementInViewport(progressArea) &&
>> +                        progressArea.scrollIntoView();
>> + $(updateButton).text(i18n['KCHUPD6007M']).prop('disabled', true);
>> +
>> +                    kimchi.updateSoftwares(function(result) {
>> +                        reloadProgressArea(result);
>> + $(updateButton).text(i18n['KCHUPD6006M']).prop('disabled', false);
>> + kimchi.topic('kimchi/softwareUpdated').publish({
>> +                            result: result
>> +                        });
>> +                    }, function() {}, reloadProgressArea);
> Do we want this function to be empty?
I'll fill it. Thanks!
>> +                }
>> +            }],
>> +            frozenFields: [{
>> +                name: 'id',
>> +                label: ' ',
>> +                'class': 'software-update-id'
>> +            }],
>> +            fields: [{
>> +                name: 'package_name',
>> +                label: i18n['KCHUPD6002M'],
>> +                'class': 'software-update-name'
>> +            }, {
>> +                name: 'version',
>> +                label: i18n['KCHUPD6003M'],
>> +                'class': 'software-update-version'
>> +            }, {
>> +                name: 'arch',
>> +                label: i18n['KCHUPD6004M'],
>> +                'class': 'software-update-arch'
>> +            }, {
>> +                name: 'repository',
>> +                label: i18n['KCHUPD6005M'],
>> +                'class': 'software-update-repos'
>> +            }],
>> +            data: softwareUpdates
> I think softwareupdates is undefined at this point. Better not to set 
> data, or set it to some explicit value
It has data at this point. The flow is:
request software packages  ==>
data received, and initialize the grid with the data

$.ajax('/host/packages', function(data) {
     new kimchi.Grid({
         data: data
     });
});

To improve UX, I'll change the flow to:
initialize the grid without any data and show "loading" icon ==>
meanwhile, request data  ==>
data received, feed grid
>> +        });
>> +    };
>> +
>> +    var listSoftwareUpdates = function() {
>> +        kimchi.listSoftwareUpdates(function(softwareUpdates) {
>> +            $.each(softwareUpdates, function(i, item) {
>> +                softwareUpdates[i]['id'] = i + 1;
>> +            });
>> +
>> +            if(softwareUpdatesGrid) {
>> +                softwareUpdatesGrid.setData(softwareUpdates);
>> +            }
>> +            else {
>> +                initSoftwareUpdatesGrid(softwareUpdates);
>> +            }
>> +
>> +            var updateButton = $('#' + softwareUpdatesGridID + 
>> '-update-button');
>> +            $(updateButton).prop('disabled', softwareUpdates.length 
>> === 0);
>> +        });
>> +    };
>> +
>>       var shutdownButtonID = '#host-button-shutdown';
>>       var restartButtonID = '#host-button-restart';
>>       var shutdownHost = function(params) {
>> @@ -191,6 +273,8 @@ kimchi.host_main = function() {
>>               kimchi.keepMonitoringHost = this['checked'];
>>           });
>>
>> +        listSoftwareUpdates();
>> +
>>           kimchi.getCapabilities(function(capabilities) {
>>               if(!capabilities['system_report_tool']) {
>>                   return;
>> @@ -204,6 +288,10 @@ kimchi.host_main = function() {
>>           listDebugReports();
>>       });
>>
>> +    kimchi.topic('kimchi/softwareUpdated').subscribe(function() {
>> +        listSoftwareUpdates();
>> +    });
>> +
>>       kimchi.getHost(function(data) {
>>           var htmlTmpl = $('#host-tmpl').html();
>>           data['logo'] = data['logo'] || '';
>> @@ -469,5 +557,6 @@ kimchi.host_main = function() {
>>               delete kimchi.hostTimer;
>>           }
>>           reportGrid && reportGrid.destroy();
>> +        softwareUpdatesGrid && softwareUpdatesGrid.destroy();
>>       });
>>   };
>> diff --git a/ui/pages/i18n.html.tmpl b/ui/pages/i18n.html.tmpl
>> index 38f71d9..c96f804 100644
>> --- a/ui/pages/i18n.html.tmpl
>> +++ b/ui/pages/i18n.html.tmpl
>> @@ -89,6 +89,16 @@ var i18n = {
>>       'KCHDR6010M': "$_("Download")",
>>       'KCHDR6011M': "$_("Report name should contain only letters, 
>> digits and/or hyphen ('-').")",
>>
>> +
>> +    'KCHUPD6001M': "$_("Software Updates")",
>> +    'KCHUPD6002M': "$_("Package Name")",
>> +    'KCHUPD6003M': "$_("Version")",
>> +    'KCHUPD6004M': "$_("Architecture")",
>> +    'KCHUPD6005M': "$_("Repository")",
>> +    'KCHUPD6006M': "$_("Update All")",
>> +    'KCHUPD6007M': "$_("Updating...")",
>> +
>> +
>>       'KCHVM6001M': "$_("This will delete the virtual machine and its 
>> virtual disks. This operation cannot be undone. Would you like to 
>> continue?")",
>>       'KCHVM6002M': "$_("Delete Confirmation")",
>>
>> diff --git a/ui/pages/tabs/host.html.tmpl b/ui/pages/tabs/host.html.tmpl
>> index 23b9853..f6ecd47 100644
>> --- a/ui/pages/tabs/host.html.tmpl
>> +++ b/ui/pages/tabs/host.html.tmpl
>> @@ -120,6 +120,23 @@
>>                       </div>
>>                   </div>
>>               </div>
>> +            <div id="software-update-section" class="host-section">
>> +                <h3 class="section-header"
>> +                    aria-controls="content-software-update">
>> +                    $_("Software Updates")
>> +                </h3>
>> +                <div id="content-software-update" 
>> class="section-content">
>> +                    <div class="section-row">
>> +                        <div class="section-value">
>> +                            <div 
>> id="software-updates-grid-container"></div>
>> +                            <div 
>> id="software-updates-progress-container" class="hidden">
>> +                                <label 
>> for="software-updates-progress-textarea">$_("Update Progress")</label>
>> +                                <textarea 
>> id="software-updates-progress-textarea" readonly></textarea>
>> +                            </div>
>> +                        </div>
>> +                    </div>
>> +                </div>
>> +            </div>
>>               <div id="debug-report-section" class="host-section 
>> hidden">
>>                   <h3 class="section-header"
>>                       aria-controls="content-sys-reports">
>
>




More information about the Kimchi-devel mailing list