[Kimchi-devel] [PATCH v4] [Kimchi] Storage Volume management

sguimaraes943 at gmail.com sguimaraes943 at gmail.com
Mon May 23 15:46:26 UTC 2016


From: Samuel Guimarães <sguimaraes943 at gmail.com>

This commit adds Storage Volume management functions Wipe, Clone, Resize and Delete with multiple selection. It also includes a filter input for each Storage Pool and Gallery View for Storage Volumes.

Signed-off-by: Samuel Guimarães <sguimaraes943 at gmail.com>
---
 model/storagevolumes.py                            |   2 +-
 ui/css/kimchi.css                                  | 369 ++++++++++++++--
 ui/css/src/modules/_storage.scss                   | 347 ++++++++++++---
 ui/js/src/kimchi.api.js                            |  50 +++
 ui/js/src/kimchi.storage_main.js                   | 465 +++++++++++++++++----
 ui/js/src/kimchi.storagepool_add_volume_main.js    |   2 +-
 ui/js/src/kimchi.storagepool_resize_volume_main.js |  59 +++
 ui/pages/i18n.json.tmpl                            |   6 +
 ui/pages/storagepool-resize-volume.html.tmpl       |  51 +++
 ui/pages/tabs/storage.html.tmpl                    | 155 +++----
 10 files changed, 1249 insertions(+), 257 deletions(-)
 create mode 100644 ui/js/src/kimchi.storagepool_resize_volume_main.js
 create mode 100644 ui/pages/storagepool-resize-volume.html.tmpl

diff --git a/model/storagevolumes.py b/model/storagevolumes.py
index da42e85..0b34c5b 100644
--- a/model/storagevolumes.py
+++ b/model/storagevolumes.py
@@ -435,7 +435,7 @@ class StorageVolumeModel(object):
                   'name': name,
                   'new_pool': new_pool,
                   'new_name': new_name}
-        taskid = add_task(u'/plugins/kimchi/storagepools/%s/storagevolumes/%s'
+        taskid = add_task(u'/plugins/kimchi/storagepools/%s/storagevolumes/%s/clone'
                           % (pool, new_name), self._clone_task, self.objstore,
                           params)
         return self.task.lookup(taskid)
diff --git a/ui/css/kimchi.css b/ui/css/kimchi.css
index 49ea39a..4798f64 100644
--- a/ui/css/kimchi.css
+++ b/ui/css/kimchi.css
@@ -2183,6 +2183,8 @@ body.wok-gallery {
 }
 
 #storage-root-container .wok-datagrid-body .handle {
+  -webkit-user-select: none;
+  -moz-user-select: none;
   user-select: none;
   position: relative;
 }
@@ -2221,74 +2223,66 @@ body.wok-gallery {
   display: none;
 }
 
+#storage-root-container .volumes input[type=checkbox][disabled].wok-checkbox + label:before {
+  content: '';
+}
+
+#storage-root-container .volumes .toggle-gallery {
+  left: 202px;
+}
+
+ at media (min-width: 1200px) {
+  #storage-root-container .volumes .toggle-gallery {
+    left: 282px;
+  }
+}
+
 #storage-root-container .volumes > .footer {
   z-index: 100;
 }
 
 #storage-root-container .volumes .volumeslist {
-  padding: 11px;
+  padding: 22px;
   max-height: 285px;
   min-height: 136px;
-  overflow: auto;
+  max-height: 505px;
+  overflow-x: hidden;
+  overflow-y: auto;
 }
 
-#storage-root-container .volumes .volume-box {
-  background: #fff;
-  padding: 4px 20px;
-  margin: 11px;
-  display: inline-block;
-  width: 409px;
-  height: 110px;
+#storage-root-container .volumes .volumeslist .row {
+  font-size: 0;
+  margin-bottom: 22px;
 }
 
-#storage-root-container .volumes .volume-title {
-  height: 46px;
-  width: 100%;
-  border-bottom: 1px solid #ccc;
-  position: relative;
+#storage-root-container .volumes .volumeslist .filter {
+  width: 344px;
+  height: 38px;
+  margin-top: 1px;
 }
 
-#storage-root-container .volumes .volume-name {
-  font-size: 15pt;
-  font-weight: 300;
-  width: 274px;
-  line-height: 46px;
-  display: inline-block;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  white-space: nowrap;
+ at media (min-width: 992px) {
+  #storage-root-container .volumes .volumeslist .filter {
+    width: 514px;
+  }
 }
 
-#storage-root-container .volumes .volume-utilization {
-  vertical-align: top;
-  text-align: right;
+#storage-root-container .volumes .pool-action {
   display: inline-block;
-  width: 90px;
-  height: 46px;
-  line-height: 46px;
+  margin-right: 20px;
 }
 
 #storage-root-container .volumes .volume-icon {
   display: inline-block;
+  vertical-align: middle;
   width: 27px;
-  height: 46px;
-  line-height: 46px;
+  height: 27px;
+  line-height: 27px;
   background-repeat: no-repeat;
   background-position: 50%;
   background-color: transparent;
 }
 
-#storage-root-container .volumes .volume-usage {
-  vertical-align: top;
-  font-size: 15pt;
-  font-weight: 400;
-  display: inline-block;
-  text-align: right;
-  line-height: 46px;
-  padding-left: 0;
-  margin-left: 5px;
-}
-
 #storage-root-container .volumes .volume-icon.icon-high {
   background-image: url("/images/theme-default/high.png");
 }
@@ -2304,13 +2298,13 @@ body.wok-gallery {
 #storage-root-container .volumes .volume-progress {
   position: absolute;
   margin: 0;
-  width: 409px;
-  top: -4px;
-  left: -20px;
+  width: 407px;
+  top: 4px;
+  left: 4px;
 }
 
 #storage-root-container .volumes .volume-progress .progress-bar-outer {
-  background: transparent;
+  background: #ddd;
   height: 6px;
   overflow: hidden;
   width: 100%;
@@ -2347,8 +2341,291 @@ body.wok-gallery {
 }
 
 #storage-root-container .volumes .pool-empty {
+  width: 100%;
+  cursor: default !important;
+}
+
+#storage-root-container .volumes .pool-empty > span {
+  width: 100%;
   text-align: center;
   line-height: 136px;
+  vertical-align: middle !important;
+}
+
+#storage-root-container .volumes .wok-gallery.wok-datagrid {
+  background: transparent;
+  margin-top: -12px;
+}
+
+#storage-root-container .volumes .wok-gallery.wok-datagrid > .wok-datagrid-header {
+  display: none;
+}
+
+#storage-root-container .volumes .wok-gallery.wok-datagrid > .wok-datagrid-body {
+  margin-left: -3px;
+}
+
+#storage-root-container .volumes .wok-gallery.wok-datagrid .wok-datagrid-body > .wok-datagrid-row {
+  position: relative;
+  cursor: pointer;
+  background: #fff !important;
+  border: 0 !important;
+  display: inline-block !important;
+  width: 415px !important;
+  margin: 12px 4px 0;
+}
+
+#storage-root-container .volumes .wok-gallery.wok-datagrid .wok-datagrid-body > .wok-datagrid-row, #storage-root-container .volumes .wok-gallery.wok-datagrid .wok-datagrid-body > .wok-datagrid-row * {
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  user-select: none;
+}
+
+#storage-root-container .volumes .wok-gallery.wok-datagrid .wok-datagrid-body > .wok-datagrid-row.selected .volume-box-border {
+  border-color: #8cc63f;
+}
+
+#storage-root-container .volumes .wok-gallery.wok-datagrid .wok-datagrid-body > .wok-datagrid-row.selected .volume-box-inner {
+  border-color: #000;
+}
+
+#storage-root-container .volumes .wok-gallery .volume-box-outer {
+  border-radius: 3px;
+  overflow: hidden;
+}
+
+#storage-root-container .volumes .wok-gallery .volume-box-border {
+  display: block;
+  border: 3px solid transparent;
+  transition: border-color .1s ease-in-out;
+}
+
+#storage-root-container .volumes .wok-gallery .volume-box-inner {
+  padding: 0 16px;
+  width: 409px;
+  height: 110px;
+  display: flex;
+  flex-flow: row wrap;
+  justify-content: space-around;
+  border: 1px solid #fff;
+  background: #fff;
+  transition: border-color .1s ease-in-out;
+}
+
+#storage-root-container .volumes .wok-gallery span.column-name,
+#storage-root-container .volumes .wok-gallery span.column-used {
+  height: 52px;
+  line-height: 52px;
+  border-bottom: 1px solid #ccc;
+}
+
+#storage-root-container .volumes .wok-gallery span.column-name {
+  width: 303px;
+  order: 1;
+}
+
+#storage-root-container .volumes .wok-gallery span.column-used {
+  width: 72px;
+  order: 2;
+}
+
+#storage-root-container .volumes .wok-gallery span.column-name label.volume-name {
+  width: 100%;
+  height: 52px;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  overflow: hidden;
+  display: block;
+  margin: 0;
+  padding-right: 6px;
+}
+
+#storage-root-container .volumes .wok-gallery span.column-allocated,
+#storage-root-container .volumes .wok-gallery span.column-capacity,
+#storage-root-container .volumes .wok-gallery span.column-format,
+#storage-root-container .volumes .wok-gallery span.column-type {
+  order: 3;
+  width: 72px;
+  margin-top: -5px;
+}
+
+#storage-root-container .volumes .wok-gallery span.gallery-header {
+  font-weight: 600;
+  display: block;
+}
+
+#storage-root-container .volumes .wok-gallery span.column-progress {
+  display: none;
+}
+
+#storage-root-container .volumes .wok-gallery .tooltip-iner {
+  font-size: 11pt;
+  padding: 6px 12px;
+}
+
+#storage-root-container .volumes .wok-list .tooltip {
+  display: none !important;
+}
+
+#storage-root-container .volumes .wok-list span.gallery-header {
+  display: none;
+}
+
+#storage-root-container .volumes .wok-list .volume-inline-progress {
+  vertical-align: middle;
+  display: inline-block;
+  margin-right: 7px;
+}
+
+#storage-root-container .volumes .wok-list .volume-inline-progress > span.wok-loading-icon {
+  margin-right: 0;
+}
+
+#storage-root-container .volumes .wok-list .volume-progress {
+  width: 100%;
+  top: 0px;
+  left: 0px;
+}
+
+#storage-root-container .volumes .wok-list .volume-progress .progress-bar-outer {
+  height: 3px;
+}
+
+#storage-root-container .volumes .wok-list .volume-box-inner {
+  font-size: 0;
+}
+
+#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-name {
+  padding-left: 41px;
+}
+
+#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row {
+  position: relative;
+  cursor: pointer;
+}
+
+#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row.selected {
+  background: #ddd !important;
+}
+
+#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span {
+  font-family: "Open Sans", Helvetica, Arial, "Lucida Grande", sans-serif;
+  line-height: 2.42857;
+  vertical-align: top;
+  font-size: 12.5pt;
+  font-weight: 400;
+}
+
+#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-name {
+  padding-left: 15px;
+}
+
+#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span,
+#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span {
+  display: inline-block;
+  vertical-align: middle;
+}
+
+#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-format,
+#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-format {
+  width: 57px;
+}
+
+ at media (min-width: 992px) {
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-format,
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-format {
+    width: 95px;
+  }
+}
+
+ at media (min-width: 1200px) {
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-format,
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-format {
+    left: 173px;
+  }
+}
+
+#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-used,
+#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-type,
+#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-capacity,
+#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-allocated,
+#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-progress,
+#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-used,
+#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-type,
+#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-capacity,
+#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-allocated,
+#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-progress {
+  width: 79px;
+  text-transform: capitalize;
+}
+
+ at media (min-width: 992px) {
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-used,
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-type,
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-capacity,
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-allocated,
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-progress,
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-used,
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-type,
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-capacity,
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-allocated,
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-progress {
+    width: 95px;
+  }
+}
+
+ at media (min-width: 1200px) {
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-used,
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-type,
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-capacity,
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-allocated,
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-progress,
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-used,
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-type,
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-capacity,
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-allocated,
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-progress {
+    left: 165px;
+  }
+}
+
+#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-name,
+#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-name {
+  width: 202px;
+}
+
+ at media (min-width: 992px) {
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-name,
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-name {
+    width: 333px;
+  }
+}
+
+ at media (min-width: 1200px) {
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-name,
+  #storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-name {
+    width: 444px;
+  }
+}
+
+#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-name label,
+#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-name label {
+  padding: 0 5px 0 0;
+  margin-right: 0;
+  margin-bottom: 0;
+  font-size: inherit;
+  font-weight: inherit;
+  width: 100%;
+  display: block;
+  height: auto;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-progress,
+#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-progress {
+  white-space: nowrap;
 }
 
 #storage-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row[data-stat="inactive"] {
diff --git a/ui/css/src/modules/_storage.scss b/ui/css/src/modules/_storage.scss
index 4a9f9e1..733b172 100644
--- a/ui/css/src/modules/_storage.scss
+++ b/ui/css/src/modules/_storage.scss
@@ -25,6 +25,8 @@
             position: relative;
         }
         .handle {
+            -webkit-user-select: none;
+            -moz-user-select: none;
             user-select: none;
             position: relative;
         }
@@ -58,66 +60,61 @@
         width: 100%;
         background: $navbar-default-toggle-hover-bg;
         display: none;
+
+        input[type=checkbox][disabled].wok-checkbox + label:before {
+            content: '';
+        }
+
+        .toggle-gallery {
+            left: 202px;
+            @media (min-width: $screen-lg) {
+                left: 282px;
+            }
+        }
+
         > .footer {
             z-index: 100;
         }
+
         .volumeslist {
-            padding: 11px;
+            padding: 22px;
             max-height: 285px;
             min-height: 136px;
-            overflow: auto;
-        }
-        .volume-box {
-            background: $navbar-inverse-toggle-icon-bar-bg;
-            padding: 4px 20px;
-            margin: 11px;
-            display: inline-block;
-            width: 409px;
-            height: 110px;
+            max-height: 505px;
+            overflow-x: hidden;
+            overflow-y: auto;
         }
-        .volume-title {
-            height: 46px;
-            width: 100%;
-            border-bottom: 1px solid $input-border;
-            position: relative;
+
+        .volumeslist .row {
+            font-size: 0;
+            margin-bottom: 22px;
         }
-        .volume-name {
-            font-size: 15pt;
-            font-weight: 300;
-            width: 274px;
-            line-height: 46px;
-            display: inline-block;
-            overflow: hidden;
-            text-overflow: ellipsis;
-            white-space: nowrap;
+
+        .volumeslist .filter {
+            width: 344px;
+            height: 38px;
+            margin-top: 1px;
+            @media (min-width: $screen-md) {
+                width: 514px;
+            }
         }
-        .volume-utilization {
-            vertical-align: top;
-            text-align: right;
+
+        .pool-action {
             display: inline-block;
-            width: 90px;
-            height: 46px;
-            line-height: 46px;
+            margin-right: 20px;
         }
+
         .volume-icon {
             display: inline-block;
+            vertical-align: middle;
             width: 27px;
-            height: 46px;
-            line-height: 46px;
+            height: 27px;
+            line-height: 27px;
             background-repeat: no-repeat;
             background-position: 50%;
             background-color: transparent;
         }
-        .volume-usage {
-            vertical-align: top;
-            font-size: 15pt;
-            font-weight: 400;
-            display: inline-block;
-            text-align: right;
-            line-height: 46px;
-            padding-left: 0;
-            margin-left: 5px;
-        }
+
         .volume-icon.icon-high {
             background-image: url('#{$wok-icon-path}/high.png');
         }
@@ -127,14 +124,16 @@
         .volume-icon.icon-low {
             background-image: url('#{$wok-icon-path}/low.png');
         }
+
         .volume-progress {
             position: absolute;
             margin: 0;
-            width: 409px;
-            top: -4px;
-            left: -20px;
+            width: 407px;
+            top: 4px;
+            left: 4px;
+
             .progress-bar-outer {
-                background: transparent;
+                background: $table-bg-hover;
                 height: 6px;
                 overflow: hidden;
                 width: 100%;
@@ -145,6 +144,7 @@
                 width: 100%;
             }
         }
+
         .volume-data {
             margin: 0;
             padding: 0;
@@ -164,10 +164,263 @@
                 }
             }
         }
-        .pool-empty {
+        .pool-empty{
+            width: 100%;
+            cursor: default !important;
+            > span  {
+            width: 100%;
             text-align: center;
             line-height: 136px;
+            vertical-align: middle !important;
+            }
+        }
+
+    .wok-gallery {
+
+        &.wok-datagrid {
+            background: transparent;
+            margin-top: -12px;
+        }
+
+        &.wok-datagrid > .wok-datagrid-header {
+            display: none;
+        }
+
+        &.wok-datagrid > .wok-datagrid-body {
+            margin-left: -3px;
+        }
+
+        &.wok-datagrid .wok-datagrid-body > .wok-datagrid-row {
+            position: relative;
+            cursor: pointer;
+            background: $body-bg !important;
+            border: 0 !important;
+            display: inline-block !important;
+            width: 415px !important;
+            margin: 12px 4px 0;
+            &, * {
+                -webkit-user-select: none;
+                -moz-user-select: none;
+                user-select: none;
+            }
+        }
+
+        &.wok-datagrid .wok-datagrid-body > .wok-datagrid-row.selected .volume-box-border {
+            border-color: $guests-color;
+        }
+
+        &.wok-datagrid .wok-datagrid-body > .wok-datagrid-row.selected .volume-box-inner {
+            border-color: $gray-base;
+        }
+
+        .volume-box-outer {
+            border-radius: 3px;
+            overflow: hidden;
+        }
+
+        .volume-box-border {
+            display: block;
+            border: 3px solid transparent;
+            transition: border-color .1s ease-in-out
+        }
+
+        .volume-box-inner {
+            padding: 0 16px;
+            width: 409px;
+            height: 110px;
+            display: flex;
+            flex-flow: row wrap;
+            justify-content: space-around;
+            border: 1px solid #fff;
+            background: #fff;
+            transition: border-color .1s ease-in-out;
+        }
+
+        span.column-name,
+        span.column-used {
+            height: 52px;
+            line-height: 52px;
+            border-bottom: 1px solid $input-border;
+            }
+
+        span.column-name {
+            width: 303px;
+            order: 1;
+        }
+
+        span.column-used {
+            width: 72px;
+            order: 2;
+        }
+
+        span.column-name label.volume-name {
+            width: 100%;
+            height: 52px;
+            white-space: nowrap;
+            text-overflow: ellipsis;
+            overflow: hidden;
+            display: block;
+            margin: 0;
+            padding-right: 6px;
         }
+
+        span.column-allocated,
+        span.column-capacity,
+        span.column-format,
+        span.column-type {
+            order: 3;
+            width: 72px;
+            margin-top: -5px;
+        }
+
+        span.gallery-header {
+            font-weight: 600;
+            display: block;
+        }
+
+        span.column-progress {
+            display: none;
+        }
+
+        .tooltip-iner {
+            font-size: 11pt;
+            padding: 6px 12px;
+        }
+
+    }
+
+    .wok-list {
+
+        .tooltip {
+            display: none !important;
+        }
+
+        span.gallery-header {
+            display: none;
+        }
+
+        .volume-inline-progress {
+            vertical-align: middle;
+            display: inline-block;
+            margin-right: 7px;
+        }
+
+        .volume-inline-progress > span.wok-loading-icon {
+            margin-right: 0;
+        }
+
+        .volume-progress {
+            width: 100%;
+            top: 0px;
+            left: 0px;
+
+            .progress-bar-outer {
+                height: 3px;
+            }
+        }
+
+        .volume-box-inner {
+            font-size: 0;
+        }
+
+        &.wok-datagrid > .wok-datagrid-header {
+
+            > span.column-name {
+                padding-left: 41px;
+            }
+
+        }
+
+        &.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row {
+            position: relative;
+            cursor: pointer;
+        }
+
+        &.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row.selected {
+            background: $table-bg-hover !important;
+        }
+
+        &.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div {
+
+            > span {
+                font-family: $font-family-sans-serif;
+                line-height: (1 + $line-height-base);
+                vertical-align: top;
+                font-size: 12.5pt;
+                font-weight: 400;
+            }
+
+            > span.column-name {
+                padding-left: 15px;
+            }
+
+        }
+
+        &.wok-datagrid > .wok-datagrid-header,
+        &.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div {
+
+            >span {
+                display: inline-block;
+                vertical-align: middle;
+            }
+
+            > span.column-format {
+                width: 57px;
+                @media (min-width: $screen-md) {
+                    width: 95px;
+                }
+                @media (min-width: $screen-lg) {
+                    left: 173px;
+                }
+            }
+
+            > span.column-used,
+            > span.column-type,
+            > span.column-capacity,
+            > span.column-allocated,
+            > span.column-progress {
+                width: 79px;
+                text-transform: capitalize;
+                @media (min-width: $screen-md) {
+                    width: 95px;
+                }
+                @media (min-width: $screen-lg) {
+                    left: 165px;
+                }
+            }
+
+            > span.column-name {
+                width: 202px;
+                @media (min-width: $screen-md) {
+                    width: 333px;
+                }
+                @media (min-width: $screen-lg) {
+                    width: 444px;
+                }
+
+                label {
+                    padding: 0 5px 0 0;
+                    margin-right: 0;
+                    margin-bottom: 0;
+                    font-size: inherit;
+                    font-weight: inherit;
+                    width: 100%;
+                    display: block;
+                    height: auto;
+                    white-space: nowrap;
+                    overflow: hidden;
+                    text-overflow: ellipsis;
+                }
+            }
+
+            > span.column-progress {
+                white-space: nowrap;
+            }
+        }
+
+    }
+
+
     }
     .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row[data-stat="inactive"] {
         color: $gray-light !important;
diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js
index 1ef3649..ce93d7d 100644
--- a/ui/js/src/kimchi.api.js
+++ b/ui/js/src/kimchi.api.js
@@ -760,6 +760,56 @@ var kimchi = {
         });
     },
 
+    cloneStoragePoolVolume: function(poolName, volumeName, data, suc, err) {
+        var url = 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName) + '/storagevolumes/' + encodeURIComponent(volumeName) + '/clone';
+        wok.requestJSON({
+            url : url,
+            type : 'POST',
+            data : JSON.stringify(data),
+            contentType : 'application/json',
+            dataType : 'json',
+            success : suc,
+            error : err
+        });
+    },
+
+    resizeStoragePoolVolume: function(poolName, volumeName, data, suc, err) {
+        var url = 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName) + '/storagevolumes/' + encodeURIComponent(volumeName) + '/resize';
+        wok.requestJSON({
+            url : url,
+            type : 'POST',
+            data : JSON.stringify(data),
+            contentType : 'application/json',
+            dataType : 'json',
+            success : suc,
+            error : err
+        });
+    },
+
+    wipeStoragePoolVolume: function(poolName, volumeName, suc, err) {
+        var url = 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName) + '/storagevolumes/' + encodeURIComponent(volumeName) + '/wipe';
+        wok.requestJSON({
+            url : url,
+            type : 'POST',
+            contentType : 'application/json',
+            dataType : 'json',
+            success : suc,
+            error : err
+        });
+    },
+
+    deleteStoragePoolVolume: function(poolName, volumeName, suc, err) {
+        var url = 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName) + '/storagevolumes/' + encodeURIComponent(volumeName);
+        wok.requestJSON({
+            url : url,
+            type : 'DELETE',
+            contentType : 'application/json',
+            dataType : 'json',
+            success : suc,
+            error : err
+        });
+    },
+
     getHostVgs: function(suc, err) {
         var url = 'plugins/kimchi/host/vgs/';
         wok.requestJSON({
diff --git a/ui/js/src/kimchi.storage_main.js b/ui/js/src/kimchi.storage_main.js
index 5312388..27e6c94 100644
--- a/ui/js/src/kimchi.storage_main.js
+++ b/ui/js/src/kimchi.storage_main.js
@@ -65,6 +65,200 @@ kimchi.doListStoragePools = function() {
 
 kimchi.storageBindClick = function() {
 
+   $('.volumes').on('click','.toggle-gallery',function(e){
+        e.preventDefault();
+        e.stopPropagation();
+        var button = $(this);
+        var volumeBlock = $(this).parent().parent().parent();
+        var text = $('span.text', button).text();
+        $(".wok-list, .wok-gallery",volumeBlock).toggleClass("wok-list wok-gallery");
+        $('span.text', button).text(text == i18n['KCHTMPL6005M'] ? i18n['KCHTMPL6004M'] : i18n['KCHTMPL6005M']);
+    });
+
+    if(wok.tabMode['storage'] === 'admin') {
+
+        $('.volumes').on('click','.volume-delete',function(e){
+            e.preventDefault();
+            e.stopPropagation();
+            var button = $(this);
+            $('.dropdown.pool-action.open .dropdown-toggle').dropdown('toggle');
+            kimchi.selectedSP = $(this).data('name');
+            var volumeBlock = $(this).data('name');
+            var volumes = $('[data-name="'+kimchi.selectedSP+'"] input:checkbox:checked').map(function(){
+              return this.value;
+            }).get();
+            kimchi.selectedVolumes = volumes.slice();
+            var formatedVolumes = '';
+            if(kimchi.selectedVolumes.length && !button.parent().is('disabled')){
+                for (i = 0; i < kimchi.selectedVolumes.length; i++) {
+                    formatedVolumes += "<li>" + kimchi.selectedVolumes[i] + "</li>";
+                }
+                var confirmMessage = i18n['KCHPOOL6010M'].replace('%1','<ul>'+formatedVolumes+'</ul>'+i18n['KCHPOOL6009M']);
+                var settings = {
+                    title : i18n['KCHAPI6001M'],
+                    content : confirmMessage,
+                    confirm : i18n['KCHAPI6002M'],
+                    cancel : i18n['KCHAPI6003M']
+                };
+                wok.confirm(settings, function() {
+                    $.each(kimchi.selectedVolumes, function(i,j) {
+                        volumes = jQuery.grep(volumes, function(value) {
+                          return value != j;
+                        });
+                        kimchi.deleteStoragePoolVolume(kimchi.selectedSP,j,function(){
+                            wok.message.success(i18n['KCHPOOL6017M'].replace('%1','<strong>'+j+'</strong>'));
+                            wok.topic('kimchi/storageVolumeDeleted').publish();
+                        },function(err){
+                            wok.message.error(err.responseJSON.reason);
+                        });
+                        if(volumes.length === 0){
+                            kimchi.selectedVolumes = '';
+                            wok.topic('kimchi/storageVolumeDeleted').publish();
+                        }
+                    });
+                });
+            }else {
+                return false;
+            }
+        });
+
+        $('.volumes').on('click','.volume-wipe',function(e){
+            e.preventDefault();
+            e.stopPropagation();
+            var button = $(this);
+            $('.dropdown.pool-action.open .dropdown-toggle').dropdown('toggle');
+            kimchi.selectedSP = $(this).data('name');
+            var volumeBlock = $(this).data('name');
+            var volumes = $('[data-name="'+kimchi.selectedSP+'"] input:checkbox:checked').map(function(){
+              return this.value;
+            }).get();
+            kimchi.selectedVolumes = volumes.slice();
+            var formatedVolumes = '';
+            if(kimchi.selectedVolumes.length && !button.parent().is('disabled')){
+                for (i = 0; i < kimchi.selectedVolumes.length; i++) {
+                    formatedVolumes += "<li>" + kimchi.selectedVolumes[i] + "</li>";
+                }
+                var confirmMessage = i18n['KCHPOOL6018M'].replace('%1','<ul>'+formatedVolumes+'</ul>'+i18n['KCHPOOL6009M']);
+                var settings = {
+                    title : i18n['KCHPOOL6019M'],
+                    content : confirmMessage,
+                    confirm : i18n['KCHAPI6002M'],
+                    cancel : i18n['KCHAPI6003M']
+                };
+                wok.confirm(settings, function() {
+                    $.each(kimchi.selectedVolumes, function(i,j) {
+                        volumes = jQuery.grep(volumes, function(value) {
+                          return value != j;
+                        });
+                        kimchi.wipeStoragePoolVolume(kimchi.selectedSP,j,function(){
+                            wok.message.success(i18n['KCHPOOL6017M'].replace('%1','<strong>'+j+'</strong>'));
+                            wok.topic('kimchi/storageVolumeWiped').publish();
+                        },function(err){
+                            wok.message.error(err.responseJSON.reason);
+                        });
+                        if(volumes.length === 0){
+                            kimchi.selectedVolumes = '';
+                            wok.topic('kimchi/storageVolumeWiped').publish();
+                        }
+                    });
+                });
+            }else {
+                return false;
+            }
+        });
+
+        $('.volumes').on('click','.volume-resize',function(e){
+            e.preventDefault();
+            e.stopPropagation();
+            var button = $(this);
+            $('.dropdown.pool-action.open .dropdown-toggle').dropdown('toggle');
+            kimchi.selectedSP = $(this).data('name');
+            var volumes = $('[data-name="'+kimchi.selectedSP+'"] input:checkbox:checked').map(function(){
+              return this.value;
+            }).get();
+            kimchi.selectedVolumes = volumes.slice(0,1);
+            if(kimchi.selectedVolumes.length && !button.parent().is('disabled')){
+                wok.window.open('plugins/kimchi/storagepool-resize-volume.html');
+            }else {
+                return false;
+            }
+        });
+
+        $('.volumes').on('click','.volume-clone',function(e){
+            e.preventDefault();
+            e.stopPropagation();
+            var button = $(this);
+            $('.dropdown.pool-action.open .dropdown-toggle').dropdown('toggle');
+            kimchi.selectedSP = $(this).data('name');
+            var volumeBlock = $(this).data('name');
+            var volumes = $('[data-name="'+kimchi.selectedSP+'"] input:checkbox:checked').map(function(){
+              return this.value;
+            }).get();
+            kimchi.volumesToClone = volumes.slice();
+            var formatedVolumes = '';
+            if(kimchi.volumesToClone.length && !button.parent().is('disabled')){
+                    $.each(kimchi.volumesToClone, function(i,j) {
+                        volumes = jQuery.grep(volumes, function(value) {
+                          return value != j;
+                        });
+                        var data = {};
+                        data = {
+                            pool: kimchi.selectedSP
+                        }
+                        kimchi.cloneStoragePoolVolume(kimchi.selectedSP,j,data,function(){
+                            wok.topic('kimchi/storageVolumeCloned').publish();
+                        },function(err){
+                            wok.message.error(err.responseJSON.reason);
+                        });
+                        if(volumes.length === 0){
+                            kimchi.volumesToClone = '';
+                            wok.topic('kimchi/storageVolumeCloned').publish();
+                        }
+                    });
+            }else {
+                return false;
+            }
+        });
+
+        $('.volumes').on('click','.wok-datagrid-row',function(e){
+            if (!$(e.target).is("input[type='checkbox']") && !$(e.target).is("label")) {
+                var volumeBlock = $(this);
+                var checkbox = volumeBlock.find('[name="selected-volume[]"]');
+                checkbox.trigger('click');
+            }
+        });
+
+        $('.volumes').on('change','[name="selected-volume[]"]',function(e){
+            var checkbox = $(this);
+            var volumeBlock = $(this).closest('.wok-datagrid-row');
+            var volumesBlock = $(this).closest('.volumeslist');
+            var disabled = [];
+            if($('[name="selected-volume[]"]:checked',volumesBlock).length > 1) {
+                disabled = ['volume-clone','volume-wipe','volume-delete'];
+                $('.volume-resize',volumesBlock).parent().addClass('disabled');
+                for (i = 0; i < disabled.length; i++) {
+                    $('.'+disabled[i],volumesBlock).parent().removeClass('disabled');
+                }
+            }else if($('[name="selected-volume[]"]:checked',volumesBlock).length === 1){
+                disabled = ['volume-resize','volume-clone','volume-wipe','volume-delete'];
+                for (i = 0; i < disabled.length; i++) {
+                    $('.'+disabled[i],volumesBlock).parent().removeClass('disabled');
+                }
+            }else {
+                disabled = ['volume-resize','volume-clone','volume-wipe','volume-delete'];
+                for (i = 0; i < disabled.length; i++) {
+                    $('.'+disabled[i],volumesBlock).parent().addClass('disabled');
+                }
+            }
+            if(checkbox.is(":checked")){
+                volumeBlock.addClass('selected');
+            }else {
+                volumeBlock.removeClass('selected');
+            }
+        });
+
+    }
+
     $('.inactive').each(function(index) {
         if ('active' === $(this).data('state')) {
             $(this).hide();
@@ -103,10 +297,10 @@ kimchi.storageBindClick = function() {
             $(this).data('type') !== 'iscsi' &&
             $(this).data('type') !== 'scsi';
         if(canAddVolume) {
-            $(this).show();
+            $(this).parent().show();
         }
         else {
-            $(this).hide();
+            $(this).parent().hide();
         }
     });
 
@@ -229,7 +423,8 @@ kimchi._generateVolumeHTML = function(volume) {
     if(volume['type'] === 'kimchi-iso') {
         return '';
     }
-    var volumeHtml = $('#volumeTmpl').html();
+    var volumeHtml = $('#volumeTmpl2').html();
+    volume.checkbox = volume.name.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi,'-'),
     volume.capacityLevel = Math.round(volume.allocation / volume.capacity * 100) || 0;
     if (volume.capacityLevel > 100) {
         volume.capacityIcon = 'icon-high';
@@ -251,77 +446,144 @@ kimchi.doListVolumes = function(poolObj) {
 
     var getOngoingVolumes = function() {
         var result = {};
+        var clone = 'status=running&target_uri=' + encodeURIComponent('^/plugins/kimchi/storagepools/.+/storagevolumes/.+/clone');
         var filter = 'status=running&target_uri=' + encodeURIComponent('^/plugins/kimchi/storagepools/' + poolName + '/*');
         kimchi.getTasksByFilter(filter, function(tasks) {
             for(var i = 0; i < tasks.length; i++) {
-                var volumeName = tasks[i].target_uri.split('/').pop();
-                result[volumeName] = tasks[i];
+                if(tasks[i].message !== 'cloning volume') {
+                    var volumeName = tasks[i].target_uri.split('/').pop();
+                    result[volumeName] = tasks[i];
 
-                if(kimchi.trackingTasks.indexOf(tasks[i].id) >= 0) {
-                    continue;
+                    if(kimchi.trackingTasks.indexOf(tasks[i].id) >= 0) {
+                        continue;
+                    }
+
+                    kimchi.trackTask(tasks[i].id, function(result) {
+                        wok.topic('kimchi/volumeTransferFinished').publish(result);
+                    }, function(result) {
+                        wok.topic('kimchi/volumeTransferError').publish(result);
+                    }, function(result) {
+                        wok.topic('kimchi/volumeTransferProgress').publish(result);
+                    });
                 }
+            }
+        }, null, true);
+        kimchi.getTasksByFilter(clone, function(tasks) {
+            for(var i = 0; i < tasks.length; i++) {
+                if(tasks[i].message === 'cloning volume') {
+                    var volumeName = tasks[i].target_uri.split('/')[6];
+                    result[volumeName] = tasks[i];
 
-                kimchi.trackTask(tasks[i].id, function(result) {
-                    wok.topic('kimchi/volumeTransferFinished').publish(result);
-                }, function(result) {
-                    wok.topic('kimchi/volumeTransferError').publish(result);
-                }, function(result) {
-                    wok.topic('kimchi/volumeTransferProgress').publish(result);
-                });
+                    if(kimchi.trackingTasks.indexOf(tasks[i].id) >= 0) {
+                        continue;
+                    }
+
+                    kimchi.trackTask(tasks[i].id, function(result) {
+                        wok.topic('kimchi/volumeCloneFinished').publish(result);
+                    }, function(result) {
+                        wok.topic('kimchi/volumeCloneError').publish(result);
+                    }, function(result) {
+                        wok.topic('kimchi/volumeCloneProgress').publish(result);
+                    });
+                }
             }
         }, null, true);
         return result;
     };
 
-    var volumeDiv = $('#volume' + poolName);
-    $(volumeDiv).empty();
+    var volumeDiv = $('#volume-' + poolName);
+    var volumeDatatable = $('.wok-datagrid > .wok-datagrid-body',volumeDiv);
     var slide = $('.volumes', poolObj);
     var handleArrow = $('.arrow-down', poolObj);
-
     kimchi.listStorageVolumes(poolName, function(result) {
         var listHtml = '';
         var ongoingVolumes = [];
         var ongoingVolumesMap = getOngoingVolumes();
         $.each(ongoingVolumesMap, function(volumeName, task) {
             ongoingVolumes.push(volumeName);
-            var volume = {
-                poolName: poolName,
-                used_by: [],
-                capacity: 0,
-                name: volumeName,
-                format: '',
-                bootable: null,
-                os_distro: '',
-                allocation: 0,
-                os_version: '',
-                path: '',
-                type: 'file',
-                capacityLevel: 0,
-                capacityIcon: ''
-            };
-            listHtml += kimchi._generateVolumeHTML(volume);
+                var volume = {
+                    poolName: poolName,
+                    used_by: [],
+                    capacity: 0,
+                    name: volumeName,
+                    format: '',
+                    bootable: null,
+                    os_distro: '',
+                    allocation: 0,
+                    os_version: '',
+                    path: '',
+                    type: 'file',
+                    capacityLevel: 0,
+                    capacityIcon: ''
+                };
+                listHtml += kimchi._generateVolumeHTML(volume);
         });
 
         $.each(result, function(index, value) {
             if (ongoingVolumes.indexOf(value.name) === -1) {
+                $(volumeDatatable).empty();
                 value.poolname = poolName;
                 listHtml += kimchi._generateVolumeHTML(value);
             }
         });
 
         if (listHtml.length > 0) {
-            volumeDiv.html(listHtml);
+            $(volumeDatatable).empty();
+            $('.filter',volumeDiv).prop('disabled',false);
+            $('.toggle-gallery',volumeDiv).prop('disabled',false);
+            $(volumeDatatable).html(listHtml);
+
         } else {
-            volumeDiv.html("<div class='pool-empty'>" + i18n['KCHPOOL6002M'] + "</div>");
+            $(volumeDatatable).empty();
+            $('.filter',volumeDiv).prop('disabled',true);
+            $('.toggle-gallery',volumeDiv).prop('disabled',true);
+            $(volumeDatatable).html("<div class='pool-empty wok-datagrid-row'><span class='volume-empty'>" + i18n['KCHPOOL6002M'] + "</span></div>");
         }
 
         $.each(ongoingVolumesMap, function(volumeName, task) {
             wok.topic('kimchi/volumeTransferProgress').publish(task);
         });
 
+        var checkbox = volumeDiv.find('[name="selected-volume[]"]');
+        checkbox.trigger('change');
+        checkbox.prop('checked',false);
         poolObj.removeClass('in');
         kimchi.changeArrow(handleArrow);
         slide.slideDown('slow');
+
+        $(window).resize(function() {
+          $('.pool-action.open', volumeDiv).removeClass('open');
+        });
+
+        $('.pool-action', volumeDiv).on('show.bs.dropdown', function () {
+            $(volumeDiv).scrollTop(0);
+            $(this).css('position','absolute');
+            $('.toggle-gallery',volumeDiv).css({
+                'position':'absolute',
+                'margin-top': '1px'
+            });
+            $(volumeDiv).bind('mousewheel DOMMouseScroll', function(e) {
+                e.preventDefault();
+            });
+        })
+
+        $('.pool-action', volumeDiv).on('hide.bs.dropdown', function () {
+            $(volumeDiv).unbind('mousewheel DOMMouseScroll');
+            $(this).removeAttr( 'style' );
+            $('.toggle-gallery',volumeDiv).removeAttr( 'style' );
+        })
+
+        volumeDivId = volumeDiv.attr('id');
+
+        volumeOptions = {
+            valueNames: ['volume-name-filter', 'volume-format-filter', 'volume-type-filter']
+        };
+        volumeFilterList = new List(volumeDivId, volumeOptions);
+
+        volumeFilterList.sort('volume-name-filter', {
+            order: "asc"
+        });
+
     }, function(err) {
         wok.message.error(err.responseJSON.reason);
     }, false);
@@ -329,53 +591,6 @@ kimchi.doListVolumes = function(poolObj) {
 
     kimchi.initLogicalPoolExtend = function() {
 
-    // $("#logicalPoolExtend").dialog({
-    //     autoOpen : false,
-    //     modal : true,
-    //     width : 600,
-    //     resizable : false,
-    //     closeText: "X",
-    //     open : function(){
-    //         $('#loading-info', '#logicalPoolExtend').removeClass('hidden');
-    //         $(".ui-dialog-titlebar-close", $("#logicalPoolExtend").parent()).removeAttr("title");
-    //         kimchi.listHostPartitions(function(data) {
-    //             $('#loading-info', '#logicalPoolExtend').addClass('hidden');
-    //             if (data.length > 0) {
-    //                 for(var i=0;i<data.length;i++){
-    //                     if (data[i].type === 'part' || data[i].type === 'disk') {
-    //                         $('.host-partition', '#logicalPoolExtend').append(wok.substitute($('#logicalPoolExtendTmpl').html(), data[i]));
-    //                     }
-    //                 }
-    //             } else {
-    //                 $('.host-partition').html(i18n['KCHPOOL6011M']);
-    //                 $('.host-partition').addClass('text-help');
-    //             }
-    //         }, function(err) {
-    //             $('#loading-info', '#logicalPoolExtend').addClass('hidden');
-    //             $('.host-partition').html(i18n['KCHPOOL6013M'] + '<br/>(' + err.responseJSON.reason + ')');
-    //             $('.host-partition').addClass('text-help');
-    //         });
-    //     },
-    //     beforeClose : function() { $('.host-partition', '#logicalPoolExtend').empty(); },
-    //     buttons : [{
-    //         class: "ui-button-primary",
-    //         text: i18n.KCHAPI6007M,
-    //         click: function(){
-    //             var devicePaths = [];
-    //             $("input[type='checkbox']:checked", "#logicalPoolExtend").each(function(){
-    //                 devicePaths.push($(this).prop('value'));
-    //             })
-    //             kimchi.updateStoragePool($("#logicalPoolExtend").dialog("option", "poolName"),{disks: devicePaths},function(data){
-    //                 var item = $("#"+$("#logicalPoolExtend").dialog("option", "poolName"));
-    //                 $(".usage", $(".storage-name", item)).text((Math.round(data.allocated/data.capacity*100)||0)+"%");
-    //                 $(".storage-text", $(".storage-capacity", item)).text(wok.changetoProperUnit(data.capacity,1));
-    //                 $(".storage-text", $(".storage-allocate", item)).text(wok.changetoProperUnit(data.allocated,1));
-    //             });
-    //             $(this).dialog("close");
-    //         }
-    //     }]
-    // });
-
     $('#logicalPoolExtend').on('hidden.bs.modal', function () {
         $('.host-partition', '#logicalPoolExtend').empty();
     });
@@ -442,6 +657,29 @@ kimchi.storage_main = function() {
         kimchi.doListVolumes(poolNode);
     });
 
+    wok.topic('kimchi/storageVolumeDeleted').subscribe(function() {
+        pool = kimchi.selectedSP;
+        var poolNode = $('.storage-li[data-name="' + pool + '"]');
+        kimchi.doListVolumes(poolNode);
+    });
+
+    wok.topic('kimchi/storageVolumeWiped').subscribe(function() {
+        pool = kimchi.selectedSP;
+        var poolNode = $('.storage-li[data-name="' + pool + '"]');
+        kimchi.doListVolumes(poolNode);
+    });
+    wok.topic('kimchi/storageVolumeCloned').subscribe(function() {
+        pool = kimchi.selectedSP;
+        var poolNode = $('.storage-li[data-name="' + pool + '"]');
+        kimchi.doListVolumes(poolNode);
+    });
+
+    wok.topic('kimchi/storageVolumeResized').subscribe(function() {
+        pool = kimchi.selectedSP;
+        var poolNode = $('.storage-li[data-name="' + pool + '"]');
+        kimchi.doListVolumes(poolNode);
+    });
+
     wok.topic('kimchi/volumeTransferProgress').subscribe(function(result) {
         var extractProgressData = function(data) {
             var sizeArray = /(\d+)\/(\d+)/g.exec(data) || [0, 0, 0];
@@ -467,22 +705,32 @@ kimchi.storage_main = function() {
         var progress = extractProgressData(result['message']);
         var size = progress['size'];
         var percent = progress['percent'];
-
-        volumeBox = $('#volume' + poolName + ' [data-volume-name="' + volumeName + '"]');
-        $('.progress-bar-inner', volumeBox).css({
-            width: percent + '%'
-        });
-        $('.progress-transferred', volumeBox).text(size);
+        volumeBox = $('#volume-' + poolName + ' [data-volume-name="' + volumeName + '"]').closest('.wok-datagrid-row');
         $('.volume-progress', volumeBox).removeClass('hidden');
+        $('.column-progress', volumeBox).removeClass('hidden');
+        $('.column-progress', '.wok-datagrid-header').removeClass('hidden');
+        $('.volume-inline-progress', volumeBox).removeClass('hidden');
+        $('.column-format > .format-text', volumeBox).text('--');
+        $('.progress-bar', volumeBox).attr('aria-valuenow',percent+'%').css('width',percent+'%');
+        $('input[type="checkbox"]',volumeBox).prop('disabled',true);
+        $(volumeBox).addClass('in-progress')
+        $('.volume-box-inner', volumeBox).attr({'data-toggle':'tooltip','data-original-title': i18n['KCHPOOL6014M'] + ' ' +size});
+        $('.tooltip-inner', volumeBox).text(i18n['KCHPOOL6014M']+' '+size);
+        $('.progress-transferred', volumeBox).text(size);
         $('.progress-status', volumeBox).text(i18n['KCHPOOL6014M']);
+        $('[data-toggle="tooltip"]',volumeBox).tooltip();
     });
 
     wok.topic('kimchi/volumeTransferFinished').subscribe(function(result) {
         var uriElements = result.target_uri.split('/');
         var poolName = uriElements[4];
         var volumeName = uriElements.pop();
-        var volumeBox = $('#volume' + poolName + ' [data-volume-name="' + volumeName + '"]');
+        volumeBox = $('#volume-' + poolName + ' [data-volume-name="' + volumeName + '"]').closest('.wok-datagrid-row');
+        $(volumeBox).removeClass('in-progress')
         $('.volume-progress', volumeBox).addClass('hidden');
+        $('.column-progress', volumeBox).addClass('hidden');
+        $('.column-progress', '.wok-datagrid-header').addClass('hidden');
+        $('.volume-inline-progress', volumeBox).addClass('hidden');
         kimchi.getStoragePoolVolume(poolName, volumeName, function(volume) {
             var html = kimchi._generateVolumeHTML(volume);
             $(volumeBox).replaceWith(html);
@@ -505,9 +753,46 @@ kimchi.storage_main = function() {
         var uriElements = result.target_uri.split('/');
         var poolName = uriElements[4];
         var volumeName = uriElements.pop();
-        volumeBox = $('#volume' + poolName + ' [data-volume-name="' + volumeName + '"]');
+        volumeBox = $('#volume-' + poolName + ' [data-volume-name="' + volumeName + '"]').closest('.wok-datagrid-row');
         $('.progress-status', volumeBox).text(i18n['KCHPOOL6015M']);
     });
+
+    wok.topic('kimchi/volumeCloneFinished').subscribe(function(result) {
+        var uriElements = result.target_uri.split('/');
+        var poolName = uriElements[4];
+        var poolNode = $('.storage-li[data-name="' + poolName + '"]');
+        kimchi.doListVolumes(poolNode);
+    });
+
+    wok.topic('kimchi/volumeCloneProgress').subscribe(function(result) {
+        var uriElements = result.target_uri.split('/');
+        var poolName = uriElements[4];
+        var volumeName = uriElements[6];
+        volumeBox = $('#volume-' + poolName + ' [data-volume-name="' + volumeName + '"]').closest('.wok-datagrid-row');
+        $('.column-progress', volumeBox).removeClass('hidden');
+        $('.column-progress', '.wok-datagrid-header').removeClass('hidden');
+        $('.volume-inline-progress', volumeBox).removeClass('hidden');
+        $('.column-format > .format-text', volumeBox).text('--');
+        $('input[type="checkbox"]',volumeBox).prop('disabled',true);
+        $(volumeBox).addClass('in-progress')
+        $('.volume-box-inner', volumeBox).attr({'data-toggle':'tooltip','data-original-title': i18n['KCHPOOL6014M'] });
+        $('.tooltip-inner', volumeBox).text(i18n['KCHPOOL6014M']);
+        $('.progress-status', volumeBox).text(i18n['KCHPOOL6014M']);
+        $('[data-toggle="tooltip"]',volumeBox).tooltip();
+    });
+
+    wok.topic('kimchi/volumeCloneError').subscribe(function(result) {
+        // Error message from Async Task status
+        if (result['message']) {
+            var errText = result['message'];
+        }
+        // Error message from standard kimchi exception
+        else {
+            var errText = result['responseJSON']['reason'];
+        }
+        result && wok.message.error(errText);
+    });
+
 };
 
 kimchi.changeArrow = function(obj) {
diff --git a/ui/js/src/kimchi.storagepool_add_volume_main.js b/ui/js/src/kimchi.storagepool_add_volume_main.js
index c398369..e167a20 100644
--- a/ui/js/src/kimchi.storagepool_add_volume_main.js
+++ b/ui/js/src/kimchi.storagepool_add_volume_main.js
@@ -180,6 +180,6 @@ kimchi.sp_add_volume_main = function() {
             uploadFile();
         }
         event.preventDefault();
-        $('#modalWindow').modal.close();
+            wok.window.close();
     });
 };
diff --git a/ui/js/src/kimchi.storagepool_resize_volume_main.js b/ui/js/src/kimchi.storagepool_resize_volume_main.js
new file mode 100644
index 0000000..791cc1d
--- /dev/null
+++ b/ui/js/src/kimchi.storagepool_resize_volume_main.js
@@ -0,0 +1,59 @@
+/*
+ * Project Kimchi
+ *
+ * Copyright IBM Corp, 2016
+ *
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+kimchi.sp_resize_volume_main = function() {
+
+    var addButton = $('#sp-resize-volume-button');
+    var size = $('#volume-size');
+    var form = $('form#form-sp-resize-volume');
+
+    $(addButton).prop('disabled',true);
+    $(size).on('keyup', function(){
+        if($(this).val().length !==0) {
+            addButton.prop('disabled', false);
+        } else{
+            addButton.prop('disabled',true);
+        }
+    });
+    $(addButton).on('click',function(e){
+        e.preventDefault();
+        e.stopPropagation();
+        $(form).submit();
+    });
+    $(form).on('submit',function(e){
+        e.preventDefault();
+        e.stopPropagation();
+        var newsize = parseInt($(size).val());
+        var bytes = newsize * 1048576;
+        var data = {};
+        data = {
+            size: bytes
+        };
+      kimchi.resizeStoragePoolVolume(kimchi.selectedSP, kimchi.selectedVolumes[0], data, function() {
+          $(size).prop('disabled', true);
+          $(addButton).prop('disabled',true);
+          wok.topic('kimchi/storageVolumeResized').publish();
+          wok.window.close();
+      }, function(err) {
+          wok.message.error(err.responseJSON.reason, '#alert-modal-container');
+          $(size).prop('disabled', false);
+          $(addButton).prop('disabled',false);
+          $(size).focus();
+      });
+  });
+}
diff --git a/ui/pages/i18n.json.tmpl b/ui/pages/i18n.json.tmpl
index e152989..a1f43d3 100644
--- a/ui/pages/i18n.json.tmpl
+++ b/ui/pages/i18n.json.tmpl
@@ -98,6 +98,8 @@
     "KCHPOOL6006M": "$_("Loading iSCSI targets...")",
     "KCHPOOL6007M": "$_("No iSCSI found. Please input one.")",
     "KCHPOOL6008M": "$_("Failed to load iSCSI targets.")",
+    "KCHPOOL6009M": "$_("Would you like to continue?")",
+    "KCHPOOL6010M": "$_("This will permanently delete the following storage volumes: %1")",
 
     "KCHPOOL6005E": "$_("Invalid NFS mount path.")",
     "KCHPOOL6006E": "$_("No logical device selected.")",
@@ -108,6 +110,10 @@
     "KCHPOOL6014M": "$_("In progress...")",
     "KCHPOOL6015M": "$_("Failed!")",
     "KCHPOOL6016M": "$_("No LVM found in the system.")",
+    "KCHPOOL6017M": "$_("Volume %1 was successfully removed.")",
+    "KCHPOOL6018M": "$_("This will permanently wipe the following storage volumes: %1")",
+    "KCHPOOL6019M": "$_("Wipe Confirmation")",
+    "KCHPOOL6020M": "$_("Volume %1 is cloning.")",
 
     "KCHVMSTOR0001E": "$_("CDROM path needs to be a valid local/remote path and cannot be blank.")",
     "KCHVMSTOR0002E": "$_("Disk pool or volume cannot be blank.")"
diff --git a/ui/pages/storagepool-resize-volume.html.tmpl b/ui/pages/storagepool-resize-volume.html.tmpl
new file mode 100644
index 0000000..7a8c7d4
--- /dev/null
+++ b/ui/pages/storagepool-resize-volume.html.tmpl
@@ -0,0 +1,51 @@
+#*
+ * Project Kimchi
+ *
+ * Copyright IBM Corp, 2016
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *#
+#unicode UTF-8
+#import gettext
+#from wok.cachebust import href
+#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
+#silent _ = t.gettext
+#silent _t = t.gettext
+<html>
+<body>
+<div id="sp-add-volume-window" class="window modal-content">
+    <form id="form-sp-resize-volume">
+        <div class="modal-header">
+            <h4 class="modal-title">$_("Resize Volume")</h4>
+        </div>
+        <div class="modal-body">
+            <span id="alert-modal-container"></span>
+            <div class="form-group">
+                <label for="volume-size">$_("Size")</label>
+                <input type="number" id="volume-size" class="form-control" name="size" />
+                <p class="help-block">
+                    <i class="fa fa-info-circle"></i> $_("The total space which can be used to store data. The unit is megabytes.")
+                </p>
+            </div>
+        </div>
+        <div class="modal-footer">
+            <button type="submit" id="sp-resize-volume-button" class="btn btn-default" disabled="disabled">$_("Ok")</button>
+            <button type="button" class="btn btn-default" data-dismiss="modal">$_("Cancel")</button>
+        </div>
+    </form>
+</div>
+<script type="text/javascript">
+    kimchi.sp_resize_volume_main();
+</script>
+</body>
+</html>
diff --git a/ui/pages/tabs/storage.html.tmpl b/ui/pages/tabs/storage.html.tmpl
index fa51e48..cf1eac7 100644
--- a/ui/pages/tabs/storage.html.tmpl
+++ b/ui/pages/tabs/storage.html.tmpl
@@ -102,90 +102,101 @@
     </div>
 </div>
 <script id="storageTmpl" type="html/text">
-        <div id="{name}" class="storage-li in" data-name="{name}" data-stat="{state}">
-               <span class='column-state' val="{state}">
-                    <span class='storage-state {state}'>
-                        <i class="fa fa-power-off"></i>
-                    </span>
-                </span><!--
-            --><span class='column-name' title="{name}" val="{name}">{name}</span><!--
-            --><span class='column-type' val="{type}">{type}</span><!--
-            --><span class='column-location' val="{path}">{path}</span><!--
-            --><span class='column-usage {state}' val="{usage}" ><span class='usage-icon {icon}'>{usage}</span>%</span><!--
-            --><span class='column-allocated' val="{allocated}">{allocated}</span><!--
-            --><span class='column-capacity' val="{capacity}">{capacity}</span><!--
-            --><span class="column-disks {state}">
-                    <div class="handle arrow-down"></div>
-                </span><!--
-            --><span class="column-action storage-button" style="display:none">
-                <span class="pull-right">
+<div id="{name}" class="storage-li in" data-name="{name}" data-stat="{state}">
+         <span class='column-state' val="{state}"><span class='storage-state {state}'><i class="fa fa-power-off"></i></span></span><!--
+    --><span class='column-name' title="{name}" val="{name}">{name}</span><!--
+    --><span class='column-type' val="{type}">{type}</span><!--
+    --><span class='column-location' val="{path}">{path}</span><!--
+    --><span class='column-usage {state}' val="{usage}" ><span class='usage-icon {icon}'>{usage}</span>%</span><!--
+    --><span class='column-allocated' val="{allocated}">{allocated}</span><!--
+    --><span class='column-capacity' val="{capacity}">{capacity}</span><!--
+    --><span class="column-disks {state}"><div class="handle arrow-down"></div></span><!--
+    --><span class="column-action storage-button" style="display:none">
+            <span class="pull-right">
                 <div class="dropdown menu-flat storage-action" data-state="{state}" data-type="{type}" data-name="{name}">
                     <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown" aria-expanded="false" aria-haspopup="true"><span class="edit-alt"></span>$_("Actions")<span class="caret"></span></button>
                     <ul class="dropdown-menu actionsheet">
-                        <li role="presentation">
-                            <a href="#" class="pool-deactivate" data-inuse="{in_use}" data-stat="{state}" data-name="{name}" data-persistent="{persistent}" href="#"><i class="fa fa-minus-circle"></i>$_("Deactivate")</a>
-                        </li>
-                        <li role="presentation">
-                            <a href="#" class="pool-activate" data-stat="{state}" data-name="{name}"><i class="fa fa-power-off"></i>$_("Activate")</a>
-                        </li>
-                        <li role="presentation">
-                            <a href="#" class="pool-add-volume" data-stat="{state}" data-name="{name}" data-type="{type}"><i class="fa fa-plus-circle"></i>$_("Add Volume")</a>
-                        </li>
-                        <li role="presentation" class="{enableExt}">
-                            <a href="#" class="pool-extend" data-stat="{state}" data-name="{name}" data-toggle="modal" data-target="#logicalPoolExtend"><i class="fa fa-external-link-square"></i>$_("Extend")</a>
-                        </li>
-                        <li role="presentation" class="critical">
-                        <a href="#" class="pool-delete" data-inuse="{in_use}" data-stat="{state}" data-name="{name}"><i class="fa fa-ban"></i>$_("Undefine")</a>
-                        </li>
+                        <li><a href="#" class="pool-deactivate" data-inuse="{in_use}" data-stat="{state}" data-name="{name}" data-persistent="{persistent}"><i class="fa fa-minus-circle"></i>$_("Deactivate")</a></li>
+                        <li><a href="#" class="pool-activate" data-stat="{state}" data-name="{name}"><i class="fa fa-power-off"></i>$_("Activate")</a></li>
+                        <li class="{enableExt}"><a href="#" class="pool-extend" data-stat="{state}" data-name="{name}" data-toggle="modal" data-target="#logicalPoolExtend"><i class="fa fa-external-link-square"></i>$_("Extend")</a></li>
+                        <li class="critical"><a href="#" class="pool-delete" data-inuse="{in_use}" data-stat="{state}" data-name="{name}"><i class="fa fa-ban"></i>$_("Undefine")</a></li>
                     </ul>
                 </div>
-                </span>
             </span>
-        <div class="volumes">
-           <div id="volume{name}" class="volumeslist" data-name="{name}" ></div>
-           <div class="clear"></div>
-        </div>
-        </div>
-</script>
-<script id="volumeTmpl" type="html/text">
-        <div class="volume-box" data-volume-name="{name}">
-            <div class="volume-title">
-                <div class="volume-name" title="{name}">{name}</div>
-                <div class="volume-utilization">
-                    <span class="volume-icon {capacityIcon}"></span>
-                    <span class="volume-usage">{capacityLevel}%</span>
+         </span>
+         <div class="volumes">
+            <div id="volume-{name}" class="volumeslist" data-name="{name}">
+                <div class="row">
+                    <div class="pull-left">
+                        <div class="dropdown menu-flat pool-action">
+                            <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown" aria-expanded="false" aria-haspopup="true"><span class="edit-alt"></span>$_("Actions")<span class="caret"></span></button>
+                            <ul class="dropdown-menu actionsheet">
+                                <li><a href="#" class="pool-add-volume" data-stat="{state}" data-name="{name}" data-type="{type}"><i class="fa fa-plus-circle"></i> $_("Add Volume")</a></li>
+                                <li class="disabled"><a href="#" class="volume-resize" data-name="{name}"><i class="fa fa-external-link-square"></i> $_("Resize")</a></li>
+                                <li class="disabled"><a href="#" class="volume-clone" data-name="{name}"><i class="fa fa-copy"></i> $_("Clone")</a></li>
+                                <li class="disabled"><a href="#" class="volume-wipe" data-name="{name}"><i class="fa fa-eraser"></i> $_("Wipe")</a></li>
+                                <li class="disabled critical"><a href="#" class="volume-delete" data-name="{name}"><i class="fa fa-minus-circle"></i> $_("Delete")</a></li>
+                            </ul>
+                        </div>
+                        <button type="button" class="btn btn-default toggle-gallery"><span class="text">$_('View Gallery')</span> <i class="fa fa-angle-right"></i><i class="fa fa-angle-right"></i><i class="fa fa-angle-right"></i></button>
+                    </div>
+                    <div class="pull-right">
+                        <label><span class="sr-only">$_('Filter:')</span>
+                            <input type="text" class="filter form-control search" placeholder="$_('Filter')">
+                        </label>
+                    </div>
                 </div>
-                <div class="volume-progress hidden">
-                    <div class="progress-bar-outer">
-                        <div class="progress-bar-inner"></div>
+                <div class="wok-datagrid wok-list">
+                    <div class="wok-datagrid-header">
+                        <span class="column-name">$_('Name')</span><!--
+                   --><span class="column-format">$_('Format')</span><!--
+                   --><span class="column-type">$_('Type')</span><!--
+                   --><span class="column-used">$_('Used')</span><!--
+                   --><span class="column-allocated">$_('Allocated')</span><!--
+                   --><span class="column-capacity">$_('Capacity')</span><!--
+                   --><span class="column-progress hidden">$_('Progress')</span>
                     </div>
-                    <div class="progress-label">
-                        <span class="progress-status"></span>
-                        <span class="progress-transferred"></span>
+                    <ul class="wok-datagrid-body list" id="volume-{name}-table">
+                    </ul>
+                </div>
+                <div class="wok-mask 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>
             </div>
-            <div class="volume-setting">
+            <div class="clear"></div>
+         </div>
+</div>
+</script>
+<script id="volumeTmpl2" type="html/text">
+<li class="wok-datagrid-row">
+    <div class="volume-progress hidden">
+        <div class="progress-bar-outer progress">
+            <div class="progress-bar-inner progress-bar" role="progressbar" aria-valuenow="0%" aria-valuemin="0%" aria-valuemax="100%" ></div>
+        </div>
+    </div>
+    <div class="volume-box-outer">
+        <div class="volume-box-border">
+            <div class="volume-box-inner" data-volume-name="{name}">
+                <span class="column-name" title="{name}">
+                    <input type="checkbox" class="wok-checkbox" name="selected-volume[]" id="{checkbox}" value="{name}">
+                    <label class="volume-name volume-name-filter" for="{checkbox}"><span class="volume-inline-progress hidden"><span class="wok-loading-icon"></span></span> {name}</label><!--
+                   --></span><!--
+                   --><span class="column-format volume-format-filter"><span class="gallery-header">$_('Format')</span><span class="format-text">{format}</span></span><!--
+                   --><span class="column-type volume-type-filter"><span class="gallery-header">$_('Type')</span>{type}</span><!--
+                   --><span class="column-used"><span role="presentation" class="volume-icon {capacityIcon}"></span> {capacityLevel}%</span><!--
+                   --><span class="column-allocated"><span class="gallery-header">$_('Allocation')</span>{allocation}</span><!--
+                   --><span class="column-capacity"><span class="gallery-header">$_('Capacity')</span>{capacity}</span><!--
+                   --><span class="column-progress hidden"><span class="progress-status"></span> <span class="progress-transferred"></span>
+                        </span>
             </div>
-            <ul class="volume-data">
-                <li>
-                    <span class="value"  title="{format}">{format}</span>
-                    <span class="key">$_("Format")</span>
-                </li>
-                <li>
-                    <span class="value"  title="{type}">{type}</span>
-                    <span class="key">$_("Type")</span>
-                </li>
-                <li>
-                    <span class="value"  title="{allocation}">{allocation}</span>
-                    <span class="key">$_("Allocation")</span>
-                </li>
-                <li>
-                    <span class="value"  title="{capacity}">{capacity}</span>
-                    <span class="key">$_("Capacity")</span>
-                </li>
-            </ul>
-      </div>
+        </div>
+    </div>
+</li>
 </script>
 <script id="logicalPoolExtendTmpl" type="html/text">
     <div>
-- 
1.9.3




More information about the Kimchi-devel mailing list