[Kimchi-devel] [PATCH] UI: Guest Snapshot

huoyuxin at linux.vnet.ibm.com huoyuxin at linux.vnet.ibm.com
Mon Nov 17 11:12:22 UTC 2014


From: Yu Xin Huo <huoyuxin at linux.vnet.ibm.com>

Signed-off-by: Yu Xin Huo <huoyuxin at linux.vnet.ibm.com>
---
 ui/css/theme-default/guest-edit.css |   34 +++++++++++++-
 ui/js/src/kimchi.api.js             |   67 +++++++++++++++++++++++++
 ui/js/src/kimchi.guest_edit_main.js |   91 +++++++++++++++++++++++++++++++++++
 ui/pages/guest-edit.html.tmpl       |   25 ++++++++++
 4 files changed, 216 insertions(+), 1 deletions(-)

diff --git a/ui/css/theme-default/guest-edit.css b/ui/css/theme-default/guest-edit.css
index b1d3931..a565c99 100644
--- a/ui/css/theme-default/guest-edit.css
+++ b/ui/css/theme-default/guest-edit.css
@@ -96,6 +96,7 @@
 }
 
 #form-guest-edit-storage .header,
+.guest-edit-snapshot .header,
 .guest-edit-interface .header {
     margin-bottom: 8px;
     padding-bottom: 2px;
@@ -105,6 +106,7 @@
 }
 
 #form-guest-edit-storage .body .item,
+.guest-edit-snapshot .body .item,
 .guest-edit-interface .body .item {
     margin: 5px 0;
 }
@@ -115,6 +117,32 @@
     width: 250px;
 }
 
+.guest-edit-snapshot .cell {
+    display: inline-block;
+}
+
+.guest-edit-snapshot .sel {
+    width: 35px;
+    vertical-align: top;
+}
+
+.guest-edit-snapshot .icon {
+    background: url('../../images/theme-default/kimchi-loading15x15.gif') no-repeat;
+    display: inline-block;
+    width: 20px;
+    height: 20px;
+    vertical-align: middle;
+    margin-left: 2px;
+}
+
+.guest-edit-snapshot .name {
+    width: 400px;
+}
+
+.guest-edit-snapshot .created {
+    width: 250px;
+}
+
 #form-guest-edit-storage .cell.dev {
     width: 60px;
 }
@@ -135,6 +163,7 @@
 }
 
 #form-guest-edit-storage .action-area,
+.guest-edit-snapshot .action-area,
 .guest-edit-interface .action-area {
     float: right;
 }
@@ -144,12 +173,14 @@
 }
 
 #form-guest-edit-storage button,
+.guest-edit-snapshot button,
 .guest-edit-interface button {
     width: 20px;
     height: 20px;
 }
 
 #form-guest-edit-storage .header button,
+.guest-edit-snapshot .header button,
 .guest-edit-interface .header button {
     margin-bottom: 1px;
 }
@@ -159,8 +190,9 @@
     margin-right: 2px;
 }
 
+.guest-edit-snapshot .hide,
 .guest-edit-interface .hide {
-    display: none;
+    display: none!important;
 }
 
 .guest-edit-permission {
diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js
index 78c6d66..f80f097 100644
--- a/ui/js/src/kimchi.api.js
+++ b/ui/js/src/kimchi.api.js
@@ -1260,5 +1260,72 @@ var kimchi = {
                 kimchi.message.error(data.responseJSON.reason);
             }
         });
+    },
+
+    listSnapshots : function(vm, suc, err) {
+        kimchi.requestJSON({
+            url : kimchi.url+'vms/'+encodeURIComponent(vm)+'/snapshots',
+            type : 'GET',
+            contentType : 'application/json',
+            dataType : 'json',
+            resend : true,
+            success : suc,
+            error : err ? err : function(data) {
+                kimchi.message.error(data.responseJSON.reason);
+            }
+        });
+    },
+
+    getCurrentSnapshot : function(vm, suc, err) {
+        kimchi.requestJSON({
+            url : kimchi.url+'vms/'+encodeURIComponent(vm)+'/snapshots/current',
+            type : 'GET',
+            contentType : 'application/json',
+            dataType : 'json',
+            resend : true,
+            success : suc,
+            error : err ? err : function(data) {
+                kimchi.message.error(data.responseJSON.reason);
+            }
+        });
+    },
+
+    revertSnapshot : function(vm, snapshot, suc, err) {
+        kimchi.requestJSON({
+            url : kimchi.url+'vms/'+encodeURIComponent(vm)+'/snapshots/'+encodeURIComponent(snapshot)+'/revert',
+            type : 'POST',
+            contentType : 'application/json',
+            dataType : 'json',
+            success : suc,
+            error : err ? err : function(data) {
+                kimchi.message.error(data.responseJSON.reason);
+            }
+        });
+    },
+
+    createSnapshot : function(vm, suc, err) {
+        kimchi.requestJSON({
+            url : kimchi.url+'vms/'+encodeURIComponent(vm)+'/snapshots',
+            type : 'POST',
+            contentType : 'application/json',
+            dataType : 'json',
+            success : suc,
+            error : err ? err : function(data) {
+                kimchi.message.error(data.responseJSON.reason);
+            }
+        });
+    },
+
+    deleteSnapshot : function(vm, snapshot, suc, err) {
+        kimchi.requestJSON({
+            url : kimchi.url+'vms/'+encodeURIComponent(vm)+'/snapshots/'+encodeURIComponent(snapshot),
+            type : 'DELETE',
+            contentType : 'application/json',
+            dataType : 'json',
+            success : suc,
+            error : err ? err : function(data) {
+                kimchi.message.error(data.responseJSON.reason);
+            }
+        });
     }
 };
diff --git a/ui/js/src/kimchi.guest_edit_main.js b/ui/js/src/kimchi.guest_edit_main.js
index 9d87a73..19fc9ba 100644
--- a/ui/js/src/kimchi.guest_edit_main.js
+++ b/ui/js/src/kimchi.guest_edit_main.js
@@ -461,6 +461,96 @@ kimchi.guest_edit_main = function() {
         });
     };
 
+    var setupSnapshot = function() {
+        var currentSnapshot;
+        var addItem = function(data, container) {
+            var itemNode = $.parseHTML(kimchi.substitute($('#snapshot-tmpl').html(),data));
+            $("."+container, "#form-guest-edit-snapshot").append(itemNode);
+            $("input:radio", itemNode).click(function(){
+                $(".revert", "#form-guest-edit-snapshot").button(currentSnapshot==data.name?"disable":"enable");
+            });
+            if(kimchi.thisVMState === "running") {
+                $("#form-guest-edit-snapshot .delete").remove();
+            }else{
+                $(".delete", itemNode).button({
+                    icons: { primary: "ui-icon-trash" },
+                    text: false
+                }).click(function(evt){
+                    evt.preventDefault();
+                    var item = $(this).parent().parent();
+                    kimchi.deleteSnapshot(kimchi.selectedGuest, item.prop("id"), function(){
+                        item.remove();
+                    });
+                });
+            }
+            return itemNode;
+        };
+        var listGeneratingSnapshots = function(){
+            $(".task", "#form-guest-edit-snapshot").empty();
+            kimchi.getTasksByFilter('status=running&target_uri='+encodeURIComponent('^/snapshots/*'), function(tasks) {
+                for(var i=0;i<tasks.length;i++){
+                    var uri = tasks[i].target_uri;
+                    addItem({
+                        name: uri.substring(uri.lastIndexOf('/')+1, uri.length),
+                        created: "",
+                        listMode: "hide",
+                        createMode: ""
+                    }, 'task');
+                    if(kimchi.trackingTasks.indexOf(tasks[i].id)==-1)
+                        kimchi.trackTask(tasks[i].id, function(task){
+                            listGeneratingSnapshots();
+                            listSnapshots();
+                        }, function(err){
+                            kimchi.message.error(err.message);
+                        });
+                }
+            });
+        };
+        var listSnapshots = function(){
+            $(".body", "#form-guest-edit-snapshot").empty();
+            kimchi.listSnapshots(kimchi.selectedGuest, function(data){
+                kimchi.getCurrentSnapshot(kimchi.selectedGuest, function(snapshot){
+                    currentSnapshot = snapshot.name;
+                    for(var i=0;i<data.length;i++){
+                        data[i].created = new Date(data[i].created*1000).toLocaleString();
+                        data[i].listMode = "";
+                        data[i].createMode = "hide";
+                        var item = addItem(data[i], 'body');
+                        if(data[i].name==currentSnapshot) $('input:radio', item).prop('checked', true);
+                    }
+                });
+            });
+        };
+        listGeneratingSnapshots();
+        listSnapshots();
+        if(kimchi.thisVMState === "running") {
+            $("#form-guest-edit-snapshot .revert").remove();
+            $("#form-guest-edit-snapshot .add").remove();
+        }else{
+            $(".revert", "#form-guest-edit-snapshot").button({
+                icons: { primary: "ui-icon-arrowthick-1-ne" },
+                text: false,
+                disabled: true
+            }).click(function(evt){
+                evt.preventDefault();
+                var item = $("input:radio:checked", "#form-guest-edit-snapshot").parent().parent();
+                kimchi.revertSnapshot(kimchi.selectedGuest, item.prop("id"), function(){
+                    currentSnapshot = item.prop("id");
+                    $(".revert", "#form-guest-edit-snapshot").button("disable");
+                });
+            });
+            $(".add", "#form-guest-edit-snapshot").button({
+                icons: { primary: "ui-icon-plusthick" },
+                text: false
+            }).click(function(evt){
+                evt.preventDefault();
+                kimchi.createSnapshot(kimchi.selectedGuest, function(){
+                    listGeneratingSnapshots();
+                });
+            });
+        }
+    };
+
     var initContent = function(guest) {
         guest['icon'] = guest['icon'] || 'images/icon-vm.png';
         $('#form-guest-edit-general').fillWithObject(guest);
@@ -496,6 +586,7 @@ kimchi.guest_edit_main = function() {
         setupInterface();
         setupPermission();
         setupPCIDevice();
+        setupSnapshot();
 
         kimchi.topic('kimchi/vmCDROMAttached').subscribe(onAttached);
         kimchi.topic('kimchi/vmCDROMReplaced').subscribe(onReplaced);
diff --git a/ui/pages/guest-edit.html.tmpl b/ui/pages/guest-edit.html.tmpl
index 512909a..796ad42 100644
--- a/ui/pages/guest-edit.html.tmpl
+++ b/ui/pages/guest-edit.html.tmpl
@@ -44,6 +44,9 @@
                 <li>
                     <a href="#form-guest-edit-pci">$_("Host PCI Device")</a>
                 </li>
+                <li>
+                    <a href="#form-guest-edit-snapshot">$_("Snapshot")</a>
+                </li>
             </ul>
             <form id="form-guest-edit-general">
                 <fieldset class="guest-edit-fieldset">
@@ -160,6 +163,17 @@
                     <div class="body"></div>
                 </div>
             </form>
+            <form id="form-guest-edit-snapshot" class="guest-edit-snapshot">
+                <div class="header">
+                    <span class="cell sel"></span>
+                    <span class="cell name">$_("Name")</span>
+                    <span class="cell created">$_("Created")</span>
+                    <button class="add action-area"></button>
+                    <button class="revert action-area" title="$_("revert")"></button>
+                </div>
+                <div class="task"></div>
+                <div class="body"></div>
+            </form>
         </div>
     </div>
     <footer>
@@ -251,6 +265,17 @@
     <button></button>
 </div>
 </script>
+<script id="snapshot-tmpl" type="text/html">
+    <div class="item" id="{name}">
+        <span class="cell sel">
+            <span class="icon {createMode}"></span>
+            <input type="radio" name="selSnap" class="{listMode}">
+        </span>
+        <span class="cell name">{name}</span>
+        <span class="cell created">{created}</span>
+        <span class="action-area"><button class="delete {listMode}"></button></span>
+    <div>
+</script>
 <script type="text/javascript">
     kimchi.guest_edit_main();
 </script>
-- 
1.7.1




More information about the Kimchi-devel mailing list