[Kimchi-devel] [PATCH v5][Kimchi] Issue# 979 - Change boot order UI

Aline Manera alinefm at linux.vnet.ibm.com
Fri Feb 3 12:55:51 UTC 2017


Hi Bianca,

Some comments:

1) I have no feedback when the operation is done. The dialog keeps open.

2) I am not able to un-check an option. Instead of that, I need to use 
the 'Remove' button.
     Is it possible to make un-check option the same as 'Remove' so we 
can remove the 'Remove' button and only let the user works on check box?

2.1) On each "Remove" button click a new request is made. The UI should 
only expose the data and get the result on "Save" button and a single 
request will be made.

3) I am not able to remove an option recently checked.

4) I was not able to get a screenshot but when I click on Edit the 
dialog opens very tiny and the loading appears outside it.
     Something like:

  ------------------------------------------------------------------
| |
|   Tiny dialog without content (only with buttons)  |
  ------------------------------------------------------------------
                <loading icon> Loading...

The dialog should be open completely and the loading message should 
appear in the center of the dialog.

5) All the 3 options are being sent to backend.
     Example, try to update a guest which has only 'hd' as boot order. I 
selected 'cdrom' and moved 'cdrom' to the first place.
     After clicking on Save, all the 3 options got saved (but I haven't 
checked 'network')

6) The 'Save' button does not work always.
     Open Edit dialog, select a new option => The Save button does not 
make any request

7) When I select "Edit" 2 requests to GET /vms/*name* are made. Only one 
should be enough.

On 01/30/2017 05:28 PM, bianca at linux.vnet.ibm.com wrote:
> From: Bianca Carvalho <bianca at linux.vnet.ibm.com>
>
> This patch adds the UI portion for supporting changing the guest boot order
> via edit guest panel.  This was based off of what Samuel had prototyped.
>
> Issue found in backend during test:
> When updating the VM even with just changing the name, the bootorder gets reset to 'hd' only.
> I tested this using the curl command and confirmed that indeed it does get reset to one entry only.
> Issue written to address this:  https://github.com/kimchi-project/kimchi/issues/1012
>
> Signed-off-by: Bianca Carvalho <bianca at linux.vnet.ibm.com>
> ---
>   ui/css/kimchi.css                    | 61 ++++++++++++++++++++++-
>   ui/css/src/modules/_edit-guests.scss | 60 +++++++++++++++++++++-
>   ui/js/src/kimchi.guest_edit_main.js  | 97 +++++++++++++++++++++++++++++++++++-
>   ui/pages/guest-edit.html.tmpl        | 26 ++++++++--
>   4 files changed, 238 insertions(+), 6 deletions(-)
>
> diff --git a/ui/css/kimchi.css b/ui/css/kimchi.css
> index fff3279..dec47fa 100644
> --- a/ui/css/kimchi.css
> +++ b/ui/css/kimchi.css
> @@ -1,7 +1,7 @@
>   /*
>    * Project Kimchi
>    *
> - * Copyright IBM Corp, 2015-2016
> + * Copyright IBM Corp, 2015-2017
>    *
>    * Licensed under the Apache License, Version 2.0 (the "License");
>    * you may not use this file except in compliance with the License.
> @@ -1557,6 +1557,65 @@ body.wok-gallery {
>     overflow: visible;
>   }
>
> +ul {
> +  cursor: default;
> +}
> +
> +.boot-order {
> +  display: block;
> +  width: 85%;
> +  font-size: 14px;
> +  line-height: 1.42857;
> +  color: #444;
> +  overflow: hidden;
> +  background-color: #fff;
> +  background-image: none;
> +  border: 1px solid #ccc;
> +  border-radius: 3px;
> +  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
> +  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
> +  -webkit-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
> +  -o-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
> +  transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
> +}
> +
> +.boot-order:focus,
> +.boot-order.focus {
> +  border-color: #66afe9;
> +  outline: 0;
> +  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
> +  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
> +}
> +
> +.boot-order > li {
> +  cursor: move;
> +  /* fallback if grab cursor is unsupported */
> +  cursor: grab;
> +  cursor: -moz-grab;
> +  cursor: -webkit-grab;
> +  border-left: 0;
> +  border-right: 0;
> +}
> +
> +.boot-order > li:first-child {
> +  border-top: 0;
> +}
> +
> +.boot-order > li:last-child {
> +  border-bottom: 0;
> +}
> +
> +.boot-order > li.ui-sortable-helper {
> +  cursor: grabbing;
> +  cursor: -moz-grabbing;
> +  cursor: -webkit-grabbing;
> +  border: 1px solid #ccc !important;
> +}
> +
> +.boot-order li i {
> +  text-align: right;
> +}
> +
>   /* Add Template Modal Window */
>   .templates-modal .modal-dialog {
>     width: 1100px;
> diff --git a/ui/css/src/modules/_edit-guests.scss b/ui/css/src/modules/_edit-guests.scss
> index 25d4d65..c8cc122 100644
> --- a/ui/css/src/modules/_edit-guests.scss
> +++ b/ui/css/src/modules/_edit-guests.scss
> @@ -1,7 +1,7 @@
>   //
>   // Project Kimchi
>   //
> -// Copyright IBM Corp, 2015-2016
> +// Copyright IBM Corp, 2015-2017
>   //
>   // Licensed under the Apache License, Version 2.0 (the "License");
>   // you may not use this file except in compliance with the License.
> @@ -429,3 +429,61 @@
>   #form-guest-storage-add .form-section .field {
>       overflow: visible;
>   }
> +
> +ul {
> +  cursor: default;
> +}
> +
> +.boot-order {
> +  display: block;
> +  width: 85%;
> +  font-size: 14px;
> +  line-height: 1.42857;
> +  color: #444;
> +  overflow: hidden;
> +  background-color: #fff;
> +  background-image: none;
> +  border: 1px solid #ccc;
> +  border-radius: 3px;
> +  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
> +  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
> +  -webkit-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
> +  -o-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
> +  transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
> +}
> +
> +.boot-order:focus,
> +.boot-order.focus {
> +  border-color: #66afe9;
> +  outline: 0;
> +  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
> +  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
> +}
> +
> +.boot-order > li {
> +  cursor: move; /* fallback if grab cursor is unsupported */
> +  cursor: grab;
> +  cursor: -moz-grab;
> +  cursor: -webkit-grab;
> +  border-left: 0;
> +  border-right: 0;
> +}
> +
> +.boot-order > li:first-child {
> +  border-top: 0;
> +}
> +
> +.boot-order > li:last-child {
> +  border-bottom: 0;
> +}
> +
> +.boot-order > li.ui-sortable-helper {
> +  cursor: grabbing;
> +  cursor: -moz-grabbing;
> +  cursor: -webkit-grabbing;
> +  border: 1px solid #ccc !important;
> +}
> +
> +.boot-order  li i {
> +  text-align: right;
> +}
> diff --git a/ui/js/src/kimchi.guest_edit_main.js b/ui/js/src/kimchi.guest_edit_main.js
> index b47d293..dfb2ca3 100644
> --- a/ui/js/src/kimchi.guest_edit_main.js
> +++ b/ui/js/src/kimchi.guest_edit_main.js
> @@ -15,6 +15,7 @@
>    * See the License for the specific language governing permissions and
>    * limitations under the License.
>    */
> +
>   kimchi.guest_edit_main = function() {
>       var authType;
>       var formTargetId;
> @@ -26,6 +27,7 @@ kimchi.guest_edit_main = function() {
>       var networkOptions = "";
>
>       clearTimeout(kimchi.vmTimeout);
> +    var bootOrderOptions = [];
>
>       $('#modalWindow').on('hidden.bs.modal', function() {
>           kimchi.setListVMAutoTimeout();
> @@ -45,7 +47,6 @@ kimchi.guest_edit_main = function() {
>
>       var submitForm = function(event) {
>
> -        // tap map, "general": 0, "storage": 1, "interface": 2, "permission": 3, "password": 4
>           var submit_map = {
>               0: generalSubmit,
>               3: permissionSubmit,
> @@ -963,6 +964,85 @@ kimchi.guest_edit_main = function() {
>           });
>       };
>
> +    var setupBootOrder = function(guest) {
> +        var guestBootOrder = guest['bootorder'];
> +        var dev = ["cdrom", "hd", "network"];
> +        var excludedDev = dev.filter(function(e){return this.indexOf(e)<0;},guestBootOrder);
> +
> +        $('#myList button').prop('disabled', true);
> +        $('#myList').empty();
> +        $.each(guestBootOrder, function(index, value) {
> +          item = $.parseHTML("<li class='list-group-item' data-value=" + value + "><input type='checkbox' class='wok-checkbox' id='checkbox-" + value + "' value='" + value + "'> <label class='check-all' for='checkbox-" + value + "'>" + value + "</label><button id='button-" + value + "' class='btn btn-link deleteBootOrderElem' style='float:right; margin-top: 3px; padding: 0;'><i class='fa fa-minus-circle'></i> Remove</button></li>");
> +          $('#myList').append(item);
> +          $('#checkbox-' + value).prop('disabled', true);
> +          $('#checkbox-' + value).prop('checked', true);
> +          $('#button-' + value).prop('disabled', false);
> +        });
> +        if (excludedDev) {
> +          $.each(excludedDev, function(index, value) {
> +            item = $.parseHTML("<li class='list-group-item' data-value=" + value + "><input type='checkbox' class='wok-checkbox' id='checkbox-" + value + "' value='" + value + "'> <label class='check-all' for='checkbox-" + value + "'>" + value + "</label><button id='button-" + value + "' class='btn btn-link deleteBootOrderElem' style='float:right; margin-top: 3px; padding: 0;'><i class='fa fa-minus-circle'></i> Remove</button></li>");
> +            $('#myList').append(item);
> +          });
> +        }
> +
> +        if (guestBootOrder.length == 1) {
> +          $('#myList button').prop('disabled', true);
> +        }
> +
> +        $('.boot-order').sortable({
> +            items: 'li',
> +            cursor: 'move',
> +            opacity: 0.6,
> +            containment: "parent",
> +            start: function(event, ui) {
> +                $(this).addClass('focus');
> +            },
> +            stop: function(event, ui) {
> +                $(this).removeClass('focus');
> +            },
> +            change: function(event, ui) {
> +                // callback once started changing order
> +            },
> +            update: function(event, ui) {
> +                // callback once finished order
> +                $(saveButton).prop('disabled', false);
> +                bootOrderOptions = [];
> +                $("#myList li").each(function() {
> +                    bootOrderOptions.push($(this).attr("data-value").toLowerCase())
> +                });
> +                bootOrderOptions.forEach(function(entry) {
> +                    console.log(entry);
> +                });
> +                var data = {
> +                    bootorder: bootOrderOptions
> +                };
> +                kimchi.updateVM(kimchi.selectedGuest, data, function() {
> +                    // wok.window.close();
> +                }, function(err) {
> +                    wok.message.error(err.responseJSON.reason,'#alert-modal-container');
> +                });
> +            }
> +        });
> +
> +        $(".deleteBootOrderElem").on('click', function(evt) {
> +            evt.preventDefault();
> +            var item = $(this).parent().attr("data-value").toLowerCase();
> +            $("#checkbox-" + item).prop('disabled', false);
> +            $("#checkbox-" + item).prop('checked', false);
> +            var index = guestBootOrder.indexOf(item);
> +            if (index !== -1) {
> +              guestBootOrder.splice(index, 1);
> +            }
> +            if (guestBootOrder.length == 1) {
> +              $('#myList button').prop('disabled', true);
> +            }
> +            var data = {
> +                bootorder: guestBootOrder
> +            };
> +            kimchi.updateVM(kimchi.selectedGuest, data, function() {});
> +        });
> +    };
> +
>       var initContent = function(guest) {
>           guest['icon'] = guest['icon'] || 'plugins/kimchi/images/icon-vm.png';
>           $('#form-guest-edit-general').fillWithObject(guest);
> @@ -1028,6 +1108,7 @@ kimchi.guest_edit_main = function() {
>           setupPermission();
>           setupPCIDevice();
>           setupSnapshot();
> +        setupBootOrder(guest);
>
>           kimchi.init_processor_tab(guest.cpu_info, $(saveButton));
>           if ((kimchi.thisVMState === "running") || (kimchi.thisVMState === "paused")) {
> @@ -1051,6 +1132,13 @@ kimchi.guest_edit_main = function() {
>           };
>       };
>
> +    $('#form-guest-edit-general').removeClass('active');
> +    $('#guest-edit-tabs > .wok-mask').show();
> +    setTimeout(function() {
> +      $('#form-guest-edit-general').addClass('active');
> +      $('#guest-edit-tabs > .wok-mask').hide();
> +    }, 500);
> +
>       kimchi.retrieveVM(kimchi.selectedGuest, initContent);
>
>       var generalSubmit = function(event) {
> @@ -1115,6 +1203,13 @@ kimchi.guest_edit_main = function() {
>                       delete changedFields.memory.current;
>                   }
>               }
> +            console.log(changedFields);
> +
> +            checkedValue = [];
> +            $("#myList input:checked").each(function() {
> +              checkedValue.push($(this).attr("value"));
> +            });
> +            changedFields.bootorder = checkedValue;
>
>               kimchi.updateVM(kimchi.selectedGuest, changedFields, function() {
>                   kimchi.listVmsAuto();
> diff --git a/ui/pages/guest-edit.html.tmpl b/ui/pages/guest-edit.html.tmpl
> index d8a482c..d67627a 100644
> --- a/ui/pages/guest-edit.html.tmpl
> +++ b/ui/pages/guest-edit.html.tmpl
> @@ -1,7 +1,7 @@
>   #*
>    * Project Kimchi
>    *
> - * Copyright IBM Corp, 2013-2016
> + * Copyright IBM Corp, 2013-2017
>    *
>    * Licensed under the Apache License, Version 2.0 (the "License");
>    * you may not use this file except in compliance with the License.
> @@ -30,7 +30,7 @@
>       </div>
>       <div class="modal-body">
>       <span id="alert-modal-container"></span>
> -<ul class="nav nav-tabs" role="tablist">
> +  <ul class="nav nav-tabs" role="tablist">
>       <li role="presentation" class="active"><a href="#form-guest-edit-general" aria-controls="form-guest-edit-general" role="tab" data-id="form-guest-edit-general" data-toggle="tab">$_("General")</a></li>
>       <li role="presentation"><a href="#form-guest-edit-storage" aria-controls="form-guest-edit-storage" role="tab" data-id="form-guest-edit-storage" data-toggle="tab">$_("Storage")</a></li>
>       <li role="presentation"><a href="#form-guest-edit-interface" aria-controls="form-guest-edit-interface" role="tab" data-id="form-guest-edit-interface" data-toggle="tab">$_("Interface")</a></li>
> @@ -40,6 +40,14 @@
>       <li role="presentation"><a href="#form-edit-processor" aria-controls="form-edit-processor" role="tab" data-id="form-edit-processor" data-toggle="tab">$_("Processor")</a></li>
>     </ul>
>           <div class="tab-content" id="guest-edit-tabs">
> +            <div class="wok-mask" role="presentation" class="hidden">
> +                <div class="wok-mask-loader-container">
> +                    <div class="wok-mask-loading">
> +                        <div class="wok-mask-loading-icon"></div>
> +                        <div class="wok-mask-loading-text">$_("Loading")...</div>
> +                    </div>
> +                </div>
> +            </div>
>               <form role="tabpanel" class="tab-pane active" id="form-guest-edit-general">
>                   <div class="form-group">
>                       <label for="guest-edit-id-textbox">$_("Name")</label>
> @@ -68,6 +76,19 @@
>                           <option value="virtio">$_("virtio")</option>
>                       </select>
>                   </div>
> +                <div class="guest-edit-bootorder tab-pane" id="form-guest-edit-bootorder">
> +                    <div id="bootOrder">
> +                        <label for="guest-edit-boot-order-textbox">Boot Order</label>
> +                            <ul id="myList" class="list-group boot-order">
> +                                <li class="list-group-item" data-value="CDROM"><input type="checkbox" id="checkbox-cdrom" value="cdrom"> CD-ROM <button id="button-cdrom" class="btn btn-link deleteBootOrderElem"><i class="fa fa-minus-circle"></i> Remove</button></li>
> +                                <li class="list-group-item" data-value="HD"><input type="checkbox" id="checkbox-hd" value="hd"> HD <button id="button-hd" class="btn btn-link deleteBootOrderElem"><i class="fa fa-minus-circle"></i> Remove</button></li>
> +                                <li class="list-group-item" data-value="Network"><input type="checkbox" id="checkbox-network" value="network"> Network <button id="button-network" class="btn btn-link deleteBootOrderElem"><i class="fa fa-minus-circle"></i> Remove</button></li>
> +                            </ul>
> +                            <p class="help-block">
> +                                <i class="fa fa-info-circle"></i> $_("Select which items for boot order and grad them when needed to order them. At least one option must be selected.")</p>
> +                            </p>
> +                    </div>
> +                </div>
>               </form>
>               <form role="tabpanel" class="tab-pane" id="form-guest-edit-storage">
>                   <div class="btn-group action-area">
> @@ -197,7 +218,6 @@
>                               $_("Current CPU must be equal or lower than the Maximum CPU value. If a topology is set, it must be also be a multiple of the 'threads' value.")
>                           </p>
>                       </div>
> -
>                       <div id="guest-max-processor-panel" class="form-group">
>                           <label for="guest-edit-max-processor-textbox">$_("Max CPU")</label>
>                           <p id="settings-readonly-help" class="hidden">$_("Unable to edit maximum CPU or CPU topology when editing a running or paused virtual machine.")</p>



More information about the Kimchi-devel mailing list