[Kimchi-devel] [V1 1/2] Edit Guest Network Inteface UI

Yu Xin Huo huoyuxin at linux.vnet.ibm.com
Wed Apr 16 09:25:53 UTC 2014


On 4/16/2014 5:17 PM, Sheldon wrote:
> On 04/16/2014 03:48 PM, Sheldon wrote:
>> On 04/15/2014 02:49 AM, Aline Manera wrote:
>>> On 04/14/2014 06:53 AM, huoyuxin at linux.vnet.ibm.com wrote:
>>>> From: Yu Xin Huo <huoyuxin at linux.vnet.ibm.com>
>>>>
>>>> Add, List, Delete, Update Guest Network Interface.
>>>>
>>>> Signed-off-by: Yu Xin Huo <huoyuxin at linux.vnet.ibm.com>
>>>> ---
>>>> ui/css/theme-default/guest-edit.css | 43 +++++++++++++++
>>>> ui/js/src/kimchi.api.js | 55 +++++++++++++++++++
>>>> ui/js/src/kimchi.guest_edit_main.js | 103 
>>>> +++++++++++++++++++++++++++++++++++
>>>> ui/pages/guest-edit.html.tmpl | 53 ++++++++++++++++++
>>>> 4 files changed, 254 insertions(+), 0 deletions(-)
>>>>
>>>> diff --git a/ui/css/theme-default/guest-edit.css 
>>>> b/ui/css/theme-default/guest-edit.css
>>>> index 0b7ba21..4b208c1 100644
>>>> --- a/ui/css/theme-default/guest-edit.css
>>>> +++ b/ui/css/theme-default/guest-edit.css
>>>> @@ -156,3 +156,46 @@
>>>> .guest-edit-cdrom-button.detach[disabled] {
>>>> background-position: -54px -108px;
>>>> }
>>>> +
>>>> +.guest-edit-interface .header {
>>>> + margin-bottom: 8px;
>>>> + padding-bottom: 2px;
>>>> + font-weight: bold;
>>>> + border-bottom: 1px solid #999999;
>>>> + overflow: hidden;
>>>> +}
>>>> +
>>>> +.guest-edit-interface .body .item {
>>>> + margin: 5px 0;
>>>> +}
>>>> +
>>>> +.guest-edit-interface .cell {
>>>> + display: inline-block;
>>>> + width: 150px;
>>>> +}
>>>> +
>>>> +.guest-edit-interface .body select {
>>>> + width: 130px;
>>>> + padding: 0px;
>>>> +}
>>>> +
>>>> +.guest-edit-interface .action-area {
>>>> + float: right;
>>>> +}
>>>> +
>>>> +.guest-edit-interface button {
>>>> + width: 20px;
>>>> + height: 20px;
>>>> +}
>>>> +
>>>> +.guest-edit-interface .header button {
>>>> + margin-bottom: 1px;
>>>> +}
>>>> +
>>>> +.guest-edit-interface .body button:not(:last-child) {
>>>> + margin-right: 2px;
>>>> +}
>>>> +
>>>> +.guest-edit-interface .hide {
>>>> + display: none;
>>>> +}
>>>> diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js
>>>> index 8c1030c..168e53d 100644
>>>> --- a/ui/js/src/kimchi.api.js
>>>> +++ b/ui/js/src/kimchi.api.js
>>>> @@ -955,5 +955,60 @@ var kimchi = {
>>>> kimchi.message.error(data.responseJSON.reason);
>>>> }
>>>> });
>>>> + },
>>>> +
>>>> + getGuestInterfaces: function(name, suc, err) {
>>>> + var url = kimchi.url+'/vms/'+encodeURIComponent(name)+'/ifaces';
>>>> + kimchi.requestJSON({
>>>> + url : url,
>>>> + type : 'GET',
>>>> + contentType : 'application/json',
>>>> + dataType : 'json',
>>>> + success : suc,
>>>> + error : err || function(data) {
>>>> + kimchi.message.error(data.responseJSON.reason);
>>>> + }
>>>> + });
>>>> + },
>>>> +
>>>> + createGuestInterface : function(name, interface, suc, err) {
>>>> + kimchi.requestJSON({
>>>> + url : kimchi.url+'/vms/'+encodeURIComponent(name)+'/ifaces',
>>>> + type : 'POST',
>>>> + contentType : 'application/json',
>>>> + dataType : 'json',
>>>> + data : JSON.stringify(interface),
>>>> + success : suc,
>>>> + error : err || function(data) {
>>>> + kimchi.message.error(data.responseJSON.reason);
>>>> + }
>>>> + });
>>>> + },
>>>> +
>>>> + deleteGuestInterface : function(vm, mac, suc, err) {
>>>> + kimchi.requestJSON({
>>>> + url : 
>>>> kimchi.url+'/vms/'+encodeURIComponent(vm)+'/ifaces/'+encodeURIComponent(mac),
>>>> + type : 'DELETE',
>>>> + contentType : 'application/json',
>>>> + dataType : 'json',
>>>> + success : suc,
>>>> + error : err ? err : function(data) {
>>>> + kimchi.message.error(data.responseJSON.reason);
>>>> + }
>>>> + });
>>>> + },
>>>> +
>>>
>>>
>>>> + updateGuestInterface : function(vm, mac, interface, suc, err) {
>>>> + $.ajax({
>>>> + url : 
>>>> kimchi.url+'/vms/'+encodeURIComponent(vm)+'/ifaces/'+encodeURIComponent(mac),
>>>> + type : 'PUT',
>>>> + contentType : 'application/json',
>>>> + data : JSON.stringify(interface),
>>>> + dataType : 'json',
>>>> + success: suc,
>>>> + error: err ? err : function(data) {
>>>> + kimchi.message.error(data.responseJSON.reason);
>>>> + }
>>>> + });
>>>
>>> The update API is not implemented on backend yet.
>>> You can remove it.
>>>
>> will implement it as soon as possible.
>>>
>>>> }
>>>> };
>>>> diff --git a/ui/js/src/kimchi.guest_edit_main.js 
>>>> b/ui/js/src/kimchi.guest_edit_main.js
>>>> index 9375c51..b051774 100644
>>>> --- a/ui/js/src/kimchi.guest_edit_main.js
>>>> +++ b/ui/js/src/kimchi.guest_edit_main.js
>>>> @@ -78,6 +78,107 @@ kimchi.guest_edit_main = function() {
>>>> });
>>>> };
>>>>
>>>> + var setupInterface = function() {
>>>> + $(".add", "#form-guest-edit-interface").button({
>>>> + icons: { primary: "ui-icon-plusthick" },
>>>> + text: false
>>>> + }).click(function(){
>>>> + addItem({
>>>> + mac: "",
>>>> + network: "",
>>>
>>>> + model: "",
>>>
>>> The model will be chosen by Kimchi automatically.
>>> It is a low level information and we should not require it from user.
>> Yese. For "create", model is chosen by Kimchi automatically.
>>
>> But for "update", it can be chosen by user, user know which is the 
>> best model for VM.
>
> Actually we let libvirt to choose a model in backend.
>
> The backend do not know which the model type is the best after we has 
> install OS on VM.
> For the VM will not store any template information, after it is create.
>
> we only know the best model type  when we create a VM.
> That's because, the template tell us the guest OS and the best model 
> for this OS.
>
> So discuss with aline, we let libvirt to choose a model for interface.
> This model may not be the best optima, but it is the best compatible.
What is the most compatible model, let me make it default, but also 
leave user the option to select.
Since different model has different advantage, no need to limit user to 
a certain one.
>
>>
>>>
>>>> + type: "",
>>>> + viewMode: "hide",
>>>> + editMode: ""
>>>> + });
>>>> + });
>>>> + var toggleEdit = function(item, on){
>>>> + $("label", item).toggleClass("hide", on);
>>>> + $("select", item).toggleClass("hide", !on);
>>>> + $(".action-area", item).toggleClass("hide");
>>>> + };
>>>> + var addItem = function(data) {
>>>> + var attrs = ["network", "model", "type"];
>>>> + var attrIndex = 0;
>>>> + var itemNode = 
>>>> $.parseHTML(kimchi.template($('#interface-tmpl').html(),data));
>>>> + $(".body", "#form-guest-edit-interface").append(itemNode);
>>>> + $("select", itemNode).first().append(networkOptions);
>>>> + if(data[attrs[attrIndex]]!=""){
>>>> + $("select", itemNode).each(function(){
>>>> + $(this).val(data[attrs[attrIndex]]);
>>>> + attrIndex++;
>>>> + });
>>>> + attrIndex = 0;
>>>> + }
>>>> + $(".edit", itemNode).button({
>>>> + icons: { primary: "ui-icon-pencil" },
>>>> + text: false
>>>> + }).click(function(){
>>>> + toggleEdit($(this).parent().parent(), true);
>>>> + });
>>>> + $(".delete", itemNode).button({
>>>> + icons: { primary: "ui-icon-trash" },
>>>> + text: false
>>>> + }).click(function(){
>>>> + var item = $(this).parent().parent();
>>>> + kimchi.deleteGuestInterface(kimchi.selectedGuest, 
>>>> item.prop("id"), function(){
>>>> + item.remove();
>>>> + });
>>>> + });
>>>> + $(".save", itemNode).button({
>>>> + icons: { primary: "ui-icon-disk" },
>>>> + text: false
>>>> + }).click(function(){
>>>> + var interface = {};
>>>> + var item = $(this).parent().parent();
>>>> + $("select", item).each(function(){
>>>> + interface[attrs[attrIndex]] = $(this).val();
>>>> + attrIndex++;
>>>> + });
>>>> + attrIndex = 0;
>>>> + var postUpdae = function(){
>>>> + $("label", item).each(function(){
>>>> + $(this).text(interface[attrs[attrIndex]]);
>>>> + attrIndex++;
>>>> + });
>>>> + attrIndex = 0;
>>>> + toggleEdit(item, false);
>>>> + };
>>>> + if(item.prop("id")==""){
>>>> + kimchi.createGuestInterface(kimchi.selectedGuest, interface, 
>>>> function(data){
>>>> + item.prop("id", data.mac);
>>>> + postUpdae();
>>>> + });
>>>> + }else{
>>>> + kimchi.updateGuestInterface(kimchi.selectedGuest, 
>>>> item.prop("id"), interface, function(){
>>>> + postUpdae();
>>>> + });
>>>> + }
>>>> + });
>>>> + $(".cancel", itemNode).button({
>>>> + icons: { primary: "ui-icon-arrowreturnthick-1-w" },
>>>> + text: false
>>>> + }).click(function(){
>>>> + var item = $(this).parent().parent();
>>>> + $("label", item).text()==="" ? item.remove() : toggleEdit(item, 
>>>> false);
>>>> + });
>>>> + };
>>>> + var networkOptions = "";
>>>> + kimchi.listNetworks(function(data){
>>>> + for(var i=0;i<data.length;i++){
>>>> + var isSlected = i==0 ? " selected" : "";
>>>> + networkOptions += "<option"+isSlected+">"+data[i].name+"</option>";
>>>> + }
>>>> + kimchi.getGuestInterfaces(kimchi.selectedGuest, function(data){
>>>> + for(var i=0;i<data.length;i++){
>>>> + data[i].viewMode = "";
>>>> + data[i].editMode = "hide";
>>>> + addItem(data[i]);
>>>> + }
>>>> + });
>>>> + });
>>>> + };
>>>> +
>>>> var initContent = function(guest) {
>>>> guest['icon'] = guest['icon'] || 'images/icon-vm.png';
>>>> for ( var prop in guest) {
>>>> @@ -101,6 +202,8 @@ kimchi.guest_edit_main = function() {
>>>> refreshCDROMs();
>>>> };
>>>>
>>>> + setupInterface();
>>>> +
>>>> kimchi.topic('kimchi/vmCDROMAttached').subscribe(onAttached);
>>>> kimchi.topic('kimchi/vmCDROMReplaced').subscribe(onReplaced);
>>>> kimchi.topic('kimchi/vmCDROMDetached').subscribe(onDetached);
>>>> diff --git a/ui/pages/guest-edit.html.tmpl 
>>>> b/ui/pages/guest-edit.html.tmpl
>>>> index 804fc39..a2949be 100644
>>>> --- a/ui/pages/guest-edit.html.tmpl
>>>> +++ b/ui/pages/guest-edit.html.tmpl
>>>> @@ -35,6 +35,9 @@
>>>> <li>
>>>> <a href="#form-guest-edit-storage">$_("Storage")</a>
>>>> </li>
>>>> + <li>
>>>> + <a href="#form-guest-edit-interface">$_("Interface")</a>
>>>> + </li>
>>>> </ul>
>>>> <form id="form-guest-edit-general">
>>>> <fieldset class="guest-edit-fieldset">
>>>> @@ -103,6 +106,15 @@
>>>> </div>
>>>> </fieldset>
>>>> </form>
>>>> + <form id="form-guest-edit-interface" class="guest-edit-interface">
>>>> + <div class="header">
>>>> + <span class="cell">$_("Network")</span>
>>>
>>>> + <span class="cell">$_("Model")</span>
>>>
>>> As I said before we should not require model info
>>>
>>>> + <span class="cell">$_("Type")</span>
>>>> + <button class="add action-area"></button>
>>>> + </div>
>>>> + <div class="body"></div>
>>>> + </form>
>>>> </div>
>>>> </div>
>>>> <footer>
>>>> @@ -133,6 +145,47 @@
>>>> </div>
>>>> </div>
>>>> </script>
>>>> +<script id="interface-tmpl" type="text/html">
>>>> + <div class="item" id="{mac}">
>>>> + <span class="cell">
>>>> + <label class="{viewMode}">{network}</label>
>>>> + <select class="{editMode}"></select>
>>>> + </span>
>>>> + <span class="cell">
>>>
>>>> + <label class="{viewMode}">{model}</label>
>>>> + <select class="{editMode}">
>>>> + <option>ne2k_pci</option>
>>>> + <option>i82551</option>
>>>> + <option>i82557b</option>
>>>> + <option>i82559er</option>
>>>> + <option selected>rtl8139</option>
>>>> + <option>e1000</option>
>>>> + <option>pcnet</option>
>>>> + <option>virtio</option>
>>>
>>> Same here.
>>>
>>>> + </select>
>>>> + </span>
>>>> + <span class="cell">
>>>> + <label class="{viewMode}">{type}</label>
>>>> + <select class="{editMode}">
>>>> + <option selected>network</option>
>>>> + <option disabled>bridge</option>
>>>> + <option disabled>user</option>
>>>> + <option disabled>ethernet</option>
>>>> + <option disabled>direct</option>
>>>> + <option disabled>hostdev</option>
>>>> + <option disabled>mcast</option>
>>>> + <option disabled>server</option>
>>>> + <option disabled>client</option>
>>>> + </select>
>>>> + </span>
>>>> + <span class="action-area {editMode}">
>>>> + <button class="save"></button><button class="cancel"></button>
>>>> + </span>
>>>> + <span class="action-area {viewMode}">
>>>> + <button class="edit"></button><button class="delete"></button>
>>>> + </span>
>>>> + <div>
>>>> +</script>
>>>>
>>>> <script type="text/javascript">
>>>> kimchi.guest_edit_main();
>>>
>>> _______________________________________________
>>> Kimchi-devel mailing list
>>> Kimchi-devel at ovirt.org
>>> http://lists.ovirt.org/mailman/listinfo/kimchi-devel
>>>
>>>
>>>
>>
>>
>
>




More information about the Kimchi-devel mailing list