Please disregard this patch, it must be sent to Ginger list.

Tks

André Teodoro

On Thu, Jan 14, 2016 at 10:22 AM, <andreteodoro.work@gmail.com> wrote:
From: Andre Teodoro <andreteodoro.work@gmail.com>

Signed-off-by: Andre Teodoro <andreteodoro.work@gmail.com>
---
 ui/config/tab-ext.xml                   |  23 +-
 ui/css/ginger.css                       | 209 +++++++-
 ui/css/src/ginger.scss                  |  70 ++-
 ui/css/src/modules/_sysmodules.scss     | 126 +++++
 ui/js/host-sysmodules.js                |  76 +++
 ui/js/util.js                           | 871 ++++++++++++++++----------------
 ui/pages/tabs/host-sysmodules.html.tmpl |  88 ++++
 7 files changed, 1012 insertions(+), 451 deletions(-)
 create mode 100644 ui/css/src/modules/_sysmodules.scss
 create mode 100644 ui/js/host-sysmodules.js
 create mode 100644 ui/pages/tabs/host-sysmodules.html.tmpl

diff --git a/ui/config/tab-ext.xml b/ui/config/tab-ext.xml
index 2247666..f3efc95 100644
--- a/ui/config/tab-ext.xml
+++ b/ui/config/tab-ext.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!--
+    <!--
 Copyright IBM Corp, 2015

 This library is free software; you can redistribute it and/or
@@ -19,22 +19,27 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 <tabs-ext>
     <functionality>Host</functionality>
     <tab>
-        <access role="admin" mode="admin"/>
-        <access role="user" mode="none"/>
+        <access role="admin" mode="admin" />
+        <access role="user" mode="none" />
         <title>Administration</title>
         <path>plugins/ginger/tabs/host-admin.html</path>
     </tab>
     <tab>
-        <access role="admin" mode="admin"/>
-        <access role="user" mode="none"/>
+        <access role="admin" mode="admin" />
+        <access role="user" mode="none" />
         <title>Network</title>
         <path>plugins/ginger/tabs/host-network.html</path>
     </tab>
     <tab>
-        <access role="admin" mode="admin"/>
-        <access role="user" mode="none"/>
-
+        <access role="admin" mode="admin" />
+        <access role="user" mode="none" />
         <title>Storage</title>
         <path>plugins/ginger/tabs/host-storage.html</path>
     </tab>
-</tabs-ext>
+    <tab>
+        <access role="admin" mode="admin" />
+        <access role="user" mode="none" />
+        <title>System Modules</title>
+        <path>plugins/ginger/tabs/host-sysmodules.html</path>
+    </tab>
+</tabs-ext>
\ No newline at end of file
diff --git a/ui/css/ginger.css b/ui/css/ginger.css
index 560fb3c..725366f 100644
--- a/ui/css/ginger.css
+++ b/ui/css/ginger.css
@@ -153,7 +153,9 @@
   background-color: #008abf;
 }

-.ginger .modal-body .nav-tabs > li.active > a, .ginger .modal-body .nav-tabs > li.active > a:hover, .ginger .modal-body .nav-tabs > li.active > a:focus {
+.ginger .modal-body .nav-tabs > li.active > a,
+.ginger .modal-body .nav-tabs > li.active > a:hover,
+.ginger .modal-body .nav-tabs > li.active > a:focus {
   border-color: -moz-use-text-color -moz-use-text-color #008abf;
 }

@@ -948,49 +950,60 @@
 #form-nw-vlan-ipv4,
 #form-nw-vlan-general,
 #form-nw-vlan-ipv6,
-#form-nw-vlan-advance {
+#form-nw-vlan-advance,
+#form-nw-bond-general,
+#form-nw-bond-ipv4,
+#form-nw-bond-ipv6,
+#form-nw-bond-advance {
   margin: 15px 0 0;
   width: 98%;
 }

 #nw-settings-window .tab-content,
-#nw-vlan-window .tab-content {
+#nw-vlan-window .tab-content,
+#nw-bond-window .tab-content {
   height: 559px;
   overflow: auto;
 }

 #nw-settings-window .tab-content .tab-pane,
-#nw-vlan-window .tab-content .tab-pane {
+#nw-vlan-window .tab-content .tab-pane,
+#nw-bond-window .tab-content .tab-pane {
   position: relative;
 }

 #nw-settings-tabs .form-horizontal .control-label,
-#nw-vlan-tabs .form-horizontal .control-label {
+#nw-vlan-tabs .form-horizontal .control-label,
+#nw-bond-tabs .form-horizontal .control-label {
   text-align: left;
   padding-top: 0px;
 }

 #nw-settings-tabs .bootgrid-table,
-#nw-vlan-tabs .bootgrid-table {
+#nw-vlan-tabs .bootgrid-table,
+#nw-bond-tabs .bootgrid-table {
   height: 140px;
   width: 99%;
   margin-left: 1%;
 }

 #nw-settings-tabs .bootgrid-table th > .column-header-anchor > .icon,
-#nw-vlan-tabs .bootgrid-table th > .column-header-anchor > .icon {
+#nw-vlan-tabs .bootgrid-table th > .column-header-anchor > .icon,
+#nw-bond-tabs .bootgrid-table th > .column-header-anchor > .icon {
   right: 40%;
 }

 #nw-settings-tabs .bootgrid-table thead,
-#nw-vlan-tabs .bootgrid-table thead {
+#nw-vlan-tabs .bootgrid-table thead,
+#nw-bond-tabs .bootgrid-table thead {
   display: block;
   width: 100%;
   padding: 0;
 }

 #nw-settings-tabs .bootgrid-table tbody,
-#nw-vlan-tabs .bootgrid-table tbody {
+#nw-vlan-tabs .bootgrid-table tbody,
+#nw-bond-tabs .bootgrid-table tbody {
   height: 120px;
   overflow: auto;
   position: absolute;
@@ -999,13 +1012,15 @@
 }

 #nw-settings-tabs .bootgrid-table tr,
-#nw-vlan-tabs .bootgrid-table tr {
+#nw-vlan-tabs .bootgrid-table tr,
+#nw-bond-tabs .bootgrid-table tr {
   width: 100%;
   display: inline-table;
 }

 #nw-settings-tabs .bootgrid-table th,
-#nw-vlan-tabs .bootgrid-table th {
+#nw-vlan-tabs .bootgrid-table th,
+#nw-bond-tabs .bootgrid-table th {
   background-color: #eee;
 }

@@ -1251,3 +1266,175 @@
   margin: 0;
   width: 160px;
 }
+
+#host-sysmodules-root-container .accordion {
+  margin: 12px 20px 12px 60px;
+  padding-bottom: 18px;
+  border-bottom: 1px solid #eee;
+  overflow: visible;
+  clear: both;
+}
+
+#host-sysmodules-root-container .accordion:first-chld {
+  margin-top: 24px;
+}
+
+#host-sysmodules-root-container .accordion > h3 {
+  margin: 0;
+  padding: 0;
+  font-size: 26px;
+  font-weight: 300;
+  height: 44px;
+  display: block;
+}
+
+#host-sysmodules-root-container .accordion > h3 a {
+  color: #3a393b;
+  text-decoration: none;
+  display: block;
+  padding: 6px 30px;
+  margin-left: -30px;
+  margin-right: -30px;
+}
+
+#host-sysmodules-root-container .accordion > h3 a span.accordion-icon {
+  margin-left: -52px;
+  vertical-align: middle;
+  display: inline-block;
+  font: normal normal normal 32px/1 FontAwesome;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  color: #3a393b;
+}
+
+#host-sysmodules-root-container .accordion > h3 a[aria-expanded="false"] span.accordion-icon:before {
+  content: "\f01a";
+}
+
+#host-sysmodules-root-container .accordion > h3 a[aria-expanded="true"] span.accordion-icon:before {
+  content: "\f01b";
+}
+
+#host-sysmodules-root-container .accordion > h3 a span.accordion-text {
+  margin-left: 23px;
+  display: inline-block;
+  vertical-align: middle;
+}
+
+#host-sysmodules-root-container .navbar-default.toolbar {
+  background-color: #008abf !important;
+}
+
+#sysmodules-content-area {
+  padding: 0;
+  list-style-type: none;
+}
+
+#sysmodules-content-area .li:nth-child(even) {
+  background-color: #fcfcfc;
+}
+
+#sysmodules-content-area .li:nth-child(odd) {
+  background-color: #fff;
+}
+
+#sysmodules-content-area .header > span,
+#sysmodules-content-area .header > div,
+#sysmodules-content-area .body > span,
+#sysmodules-content-area .body > div {
+  padding: 6px 2px;
+  display: inline-block;
+  font-family: "Open Sans", Helvetica, Arial, "Lucida Grande", sans-serif;
+}
+
+#sysmodules-content-area .header {
+  border-top: 0 none;
+}
+
+#sysmodules-content-area .header > span,
+#sysmodules-content-area .header > div {
+  vertical-align: bottom;
+  height: 36px;
+  font-weight: 300;
+  font-size: 12.5pt;
+  line-height: 1.42857;
+  border-bottom: 0;
+  border-top: 0;
+}
+
+#sysmodules-content-area .body {
+  border-top: 1px solid #eee;
+}
+
+#sysmodules-content-area .body > span,
+#sysmodules-content-area .body > div {
+  vertical-align: middle;
+  font-size: 11pt;
+  line-height: 2.42857;
+  font-weight: 400;
+}
+
+#sysmodules-content-area .btn-group {
+  margin-bottom: 20px;
+}
+
+#sysmodules-content-area .column-name {
+  width: 30%;
+}
+
+#sysmodules-content-area .column-depends {
+  width: 30%;
+}
+
+#sysmodules-content-area .column-details {
+  width: 12%;
+  vertical-align: middle;
+  text-align: center;
+}
+
+#sysmodules-content-area .column-version {
+  width: 14%;
+}
+
+#sysmodules-content-area .column-actions {
+  width: 14%;
+}
+
+#sysmodules-content-area .sysmodules-details {
+  width: 100%;
+  padding: 22px;
+  background: #ddd;
+}
+
+#sysmodules-content-area .details-list {
+  max-height: 285px;
+  min-height: 140px;
+  background: #fff;
+  padding: 0;
+  overflow-x: hidden;
+  overflow-y: auto;
+}
+
+#sysmodules-content-area .arrow-down,
+#sysmodules-content-area .arrow-up {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  cursor: pointer;
+}
+
+#sysmodules-content-area .arrow-down:before {
+  content: "\f078";
+}
+
+#sysmodules-content-area .arrow-up:before {
+  content: "\f077";
+}
+
+#sysmodules-content-area .btn .fa-upload {
+  margin-right: 10px;
+  font-size: 20px;
+}
diff --git a/ui/css/src/ginger.scss b/ui/css/src/ginger.scss
index 610ecea..862f298 100644
--- a/ui/css/src/ginger.scss
+++ b/ui/css/src/ginger.scss
@@ -1,4 +1,4 @@
-/*
+    /*
  * Copyright IBM Corp, 2015
  *
  * This library is free software; you can redistribute it and/or
@@ -18,10 +18,8 @@

 // Core variables
 @import "../../../../../../../ui/css/src/modules/wok-variables";
-
 // Compass Mixins
 @import "../../../../../../../ui/css/src/vendor/compass-mixins/lib/compass";
-
 .ui-tooltip {
     width: "";
     display: inline-block;
@@ -144,14 +142,68 @@
 }

 .ginger {
-  div.modal-footer {
-    background-color: #008abf;
-  }
-  .modal-body .nav-tabs > li.active > a, .modal-body .nav-tabs > li.active > a:hover, .modal-body .nav-tabs > li.active > a:focus{
-    border-color:-moz-use-text-color -moz-use-text-color #008abf;
-  }
+    div.modal-footer {
+        background-color: #008abf;
+    }
+    .modal-body .nav-tabs > li.active > a,
+    .modal-body .nav-tabs > li.active > a:hover,
+    .modal-body .nav-tabs > li.active > a:focus {
+        border-color: -moz-use-text-color -moz-use-text-color #008abf;
+    }
+}
+
+@mixin ginger-accordion() {
+    margin: 12px 20px 12px 60px;
+    padding-bottom: 18px;
+    border-bottom: 1px solid $table-border-color;
+    overflow: visible;
+    clear: both;
+    &:first-chld {
+        margin-top: 24px;
+    }
+    > h3 {
+        margin: 0;
+        padding: 0;
+        font-size: 26px;
+        font-weight: 300;
+        height: 44px;
+        display: block;
+        a {
+            color: $brand-primary;
+            text-decoration: none;
+            display: block;
+            padding: 6px 30px;
+            margin-left: -30px;
+            margin-right: -30px;
+            span.accordion-icon {
+                margin-left: -52px;
+                vertical-align: middle;
+                display: inline-block;
+                font: normal normal normal 32px/1 FontAwesome;
+                text-rendering: auto;
+                -webkit-font-smoothing: antialiased;
+                color: $brand-primary;
+            }
+            &[aria-expanded="false"] {
+                span.accordion-icon:before {
+                    content: "\f01a";
+                }
+            }
+            &[aria-expanded="true"] {
+                span.accordion-icon:before {
+                    content: "\f01b";
+                }
+            }
+            span.accordion-text {
+                margin-left: 23px;
+                display: inline-block;
+                vertical-align: middle;
+            }
+        }
+    }
 }

 @import "modules/administration";
 @import "modules/network";
 @import "modules/storage";
+@import "modules/sysmodules";
\ No newline at end of file
diff --git a/ui/css/src/modules/_sysmodules.scss b/ui/css/src/modules/_sysmodules.scss
new file mode 100644
index 0000000..5858dcc
--- /dev/null
+++ b/ui/css/src/modules/_sysmodules.scss
@@ -0,0 +1,126 @@
+//
+// Project Ginger
+//
+// Copyright IBM, Corp. 2016
+//
+// Code derived from Project Kimchi
+//
+// 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.
+//
+#host-sysmodules-root-container {
+    .accordion {
+        @include ginger-accordion();
+    }
+    .navbar-default.toolbar {
+        background-color: $hosts-color !important;
+    }
+}
+
+#sysmodules-content-area {
+    padding: 0;
+    list-style-type: none;
+    .li:nth-child(even) {
+        background-color: #fcfcfc;
+    }
+    .li:nth-child(odd) {
+        background-color: #fff;
+    }
+    .header,
+    .body {
+        > span,
+        > div {
+            padding: 6px 2px;
+            display: inline-block;
+            font-family: $font-family-sans-serif;
+        }
+    }
+    .header {
+        border-top: 0 none;
+        > span,
+        > div {
+            vertical-align: bottom;
+            height: 36px;
+            font-weight: 300;
+            font-size: 12.5pt;
+            line-height: 1.42857;
+            border-bottom: 0;
+            border-top: 0;
+        }
+    }
+    .body {
+        border-top: 1px solid #eee;
+        > span,
+        > div {
+            vertical-align: middle;
+            font-size: 11pt;
+            line-height: 2.42857;
+            font-weight: 400;
+        }
+    }
+    .btn-group {
+        margin-bottom: 20px;
+    }
+    .actBtn {
+        width: 115px;
+    }
+    .column-name {
+        width: 30%;
+    }
+    .column-depends {
+        width: 30%;
+    }
+    .column-details {
+        width: 12%;
+        vertical-align: middle;
+        text-align: center;
+    }
+    .column-version {
+        width: 14%;
+    }
+    .column-actions {
+        width: 14%;
+    }
+    .sysmodules-details {
+        width: 100%;
+        padding: 22px;
+        background: $table-bg-active;
+    }
+    .details-list {
+        max-height: 285px;
+        min-height: 140px;
+        background: $table-bg;
+        padding: 0;
+        overflow-x: hidden;
+        overflow-y: auto;
+    }
+    .arrow-down,
+    .arrow-up {
+        display: inline-block;
+        font: normal normal normal 14px/1 FontAwesome;
+        font-size: inherit;
+        text-rendering: auto;
+        -webkit-font-smoothing: antialiased;
+        -moz-osx-font-smoothing: grayscale;
+        cursor: pointer;
+    }
+    .arrow-down:before {
+        content: "\f078";
+    }
+    .arrow-up:before {
+        content: "\f077";
+    }
+    .btn .fa-upload {
+        margin-right: 10px;
+        font-size: 20px;
+    }
+}
\ No newline at end of file
diff --git a/ui/js/host-sysmodules.js b/ui/js/host-sysmodules.js
new file mode 100644
index 0000000..3644a02
--- /dev/null
+++ b/ui/js/host-sysmodules.js
@@ -0,0 +1,76 @@
+/*
+ * Copyright IBM Corp, 2016
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+ginger.initSysmodules = function() {
+    $(".content-area", "#gingerHostAdmin").css("height", "100%");
+    ginger.loadSysmodules();
+};
+
+ginger.loadSysmodules = function() {
+    ginger.getSysmodules(function(data) {
+        $("#sysmodules-body").empty();
+        for (var i = 0; i < data.length; i++) {
+            var tempNode = $.parseHTML(wok.substitute($("#sysmodulesItem").html(), data[i]));
+            $("#sysmodules-body").append(tempNode);
+
+            $(".details-list", tempNode).append('Details');
+
+            $(".btn-unload").on("click", function(event) {
+                event.preventDefault();
+                event.stopImmediatePropagation();
+                var sysmoduleItem = $(this).parent();
+
+                ginger.removeSysmodule(sysmoduleItem.prop("id"), function() {
+                    sysmoduleItem.remove();
+                }, function(error) {
+                    wok.message.error('Unable to unload the module.');
+                });
+            });
+        }
+
+        $('.load-modules-btn').on('click', function(event) {
+            // TODO: Implement load modules action
+        });
+
+        $('.arrow').on('click', function(event) {
+            var that = $(this).parent().parent();
+            var slide = $('.sysmodules-details', $(this).parent().parent());
+            if (that.hasClass('in')) {
+                that.css('height', 'auto');
+                that.removeClass('in');
+                ginger.changeArrow($('.arrow-down', that));
+                slide.slideDown('slow');
+            } else {
+                slide.slideUp('slow', function() {
+                    that.css('height', '');
+                });
+                that.addClass('in');
+                ginger.changeArrow($('.arrow-up', that));
+            }
+        });
+    });
+
+};
+
+ginger.changeArrow = function(obj) {
+    if ($(obj).hasClass('arrow-down')) {
+        $(obj).removeClass('arrow-down').addClass('arrow-up');
+    } else {
+        $(obj).removeClass('arrow-up').addClass('arrow-down');
+    }
+}
\ No newline at end of file
diff --git a/ui/js/util.js b/ui/js/util.js
index ed12bd4..8e1cc17 100644
--- a/ui/js/util.js
+++ b/ui/js/util.js
@@ -21,27 +21,27 @@ ginger.hostarch = null;
 ginger.selectedInterface = null;

 trackingTasks = [];
-ginger.getFirmware = function(suc, err){
+ginger.getFirmware = function(suc, err) {
     wok.requestJSON({
-        url : 'plugins/ginger/firmware',
-        type : 'GET',
-        contentType : 'application/json',
-        dataType : 'json',
-        resend : true,
-        success : suc,
-        error : err || function(data) {
+        url: 'plugins/ginger/firmware',
+        type: 'GET',
+        contentType: 'application/json',
+        dataType: 'json',
+        resend: true,
+        success: suc,
+        error: err || function(data) {
             wok.message.error(data.responseJSON.reason);
         }
     });
 };

-ginger.updateFirmware = function(content, suc, err){
+ginger.updateFirmware = function(content, suc, err) {
     $.ajax({
-        url : "plugins/ginger/firmware",
-        type : 'PUT',
-        contentType : 'application/json',
-        dataType : 'json',
-        data : JSON.stringify(content),
+        url: "plugins/ginger/firmware",
+        type: 'PUT',
+        contentType: 'application/json',
+        dataType: 'json',
+        data: JSON.stringify(content),
         success: suc,
         error: err || function(data) {
             wok.message.error(data.responseJSON.reason);
@@ -50,82 +50,82 @@ ginger.updateFirmware = function(content, suc, err){
 };

 ginger.fwProgress = function(suc, err, progress) {
-    var taskID = -1;
-    var onResponse = function(data) {
-        taskID = data['id'];
-        trackTask();
-    };
-
-    var trackTask = function() {
-        ginger.getTask(taskID, onTaskResponse, err);
-    };
-
-    var onTaskResponse = function(result) {
-        var taskStatus = result['status'];
-        switch(taskStatus) {
-        case 'running':
-            progress && progress(result);
-            setTimeout(function() {
-                trackTask();
-            }, 1000);
-            break;
-        case 'finished':
-        case 'failed':
-            suc(result);
-            break;
-        default:
-            break;
-        }
+        var taskID = -1;
+        var onResponse = function(data) {
+            taskID = data['id'];
+            trackTask();
+        };
+
+        var trackTask = function() {
+            ginger.getTask(taskID, onTaskResponse, err);
+        };
+
+        var onTaskResponse = function(result) {
+            var taskStatus = result['status'];
+            switch (taskStatus) {
+                case 'running':
+                    progress && progress(result);
+                    setTimeout(function() {
+                        trackTask();
+                    }, 1000);
+                    break;
+                case 'finished':
+                case 'failed':
+                    suc(result);
+                    break;
+                default:
+                    break;
+            }
+        };
+
+        wok.requestJSON({
+            url: 'plugins/ginger/fwprogress',
+            type: "GET",
+            contentType: "application/json",
+            dataType: "json",
+            success: onResponse,
+            error: err
+        });
+    },
+
+
+    ginger.listBackupArchives = function(suc, err) {
+        wok.requestJSON({
+            url: 'plugins/ginger/backup/archives',
+            type: 'GET',
+            contentType: 'application/json',
+            dataType: 'json',
+            resend: true,
+            success: suc,
+            error: err || function(data) {
+                wok.message.error(data.responseJSON.reason);
+            }
+        });
     };

-    wok.requestJSON({
-        url : 'plugins/ginger/fwprogress',
-        type : "GET",
-        contentType : "application/json",
-        dataType : "json",
-        success : onResponse,
-        error : err
-    });
-},
-
-
-ginger.listBackupArchives = function(suc, err){
-    wok.requestJSON({
-        url : 'plugins/ginger/backup/archives',
-        type : 'GET',
-        contentType : 'application/json',
-        dataType : 'json',
-        resend : true,
-        success : suc,
-        error : err || function(data) {
-            wok.message.error(data.responseJSON.reason);
-        }
-    });
-};
-
 ginger.createBackupArchive = function(bak, suc, err) {
     wok.requestJSON({
-        url : 'plugins/ginger/backup/archives',
-        type : 'POST',
-        contentType : 'application/json',
-        dataType : 'json',
-        data : JSON.stringify(bak),
-        success : suc,
-        error : err || function(data) {
+        url: 'plugins/ginger/backup/archives',
+        type: 'POST',
+        contentType: 'application/json',
+        dataType: 'json',
+        data: JSON.stringify(bak),
+        success: suc,
+        error: err || function(data) {
             wok.message.error(data.responseJSON.reason);
         }
     });
 };

-ginger.getBackupArchiveFile = function(id, suc, err){
+ginger.getBackupArchiveFile = function(id, suc, err) {
     wok.requestJSON({
-        url : 'plugins/ginger/backup/archives/' + encodeURIComponent(id) + '/file',
-        type : 'GET',
-        contentType : 'application/json',
-        dataType : 'json',
-        resend : true,
-        success : suc,
-        error : err || function(data) {
+        url: 'plugins/ginger/backup/archives/' + encodeURIComponent(id) + '/file',
+        type: 'GET',
+        contentType: 'application/json',
+        dataType: 'json',
+        resend: true,
+        success: suc,
+        error: err || function(data) {
             wok.message.error(data.responseJSON.reason);
         }
     });
@@ -133,12 +133,12 @@ ginger.getBackupArchiveFile = function(id, suc, err){

 ginger.deleteBackupArchive = function(id, suc, err) {
     wok.requestJSON({
-        url : 'plugins/ginger/backup/archives/' + encodeURIComponent(id),
-        type : 'DELETE',
-        contentType : 'application/json',
-        dataType : 'json',
-        success : suc,
-        error : err || function(data) {
+        url: 'plugins/ginger/backup/archives/' + encodeURIComponent(id),
+        type: 'DELETE',
+        contentType: 'application/json',
+        dataType: 'json',
+        success: suc,
+        error: err || function(data) {
             wok.message.error(data.responseJSON.reason);
         }
     });
@@ -146,13 +146,13 @@ ginger.deleteBackupArchive = function(id, suc, err) {

 ginger.deleteBackupArchives = function(content, suc, err) {
     wok.requestJSON({
-        url : 'plugins/ginger/backup/discard_archives',
-        type : 'POST',
-        contentType : 'application/json',
-        dataType : 'json',
-        data : JSON.stringify(content),
-        success : suc,
-        error : err || function(data) {
+        url: 'plugins/ginger/backup/discard_archives',
+        type: 'POST',
+        contentType: 'application/json',
+        dataType: 'json',
+        data: JSON.stringify(content),
+        success: suc,
+        error: err || function(data) {
             wok.message.error(data.responseJSON.reason);
         }
     });
@@ -160,25 +160,25 @@ ginger.deleteBackupArchives = function(content, suc, err) {

 ginger.getInterfaces = function(suc, err) {
     wok.requestJSON({
-        url : 'plugins/ginger/network/interfaces',
-        type : 'GET',
-        contentType : 'application/json',
-        dataType : 'json',
-        resend : true,
-        success : suc,
-        error : err || function(data) {
+        url: 'plugins/ginger/network/interfaces',
+        type: 'GET',
+        contentType: 'application/json',
+        dataType: 'json',
+        resend: true,
+        success: suc,
+        error: err || function(data) {
             wok.message.error(data.responseJSON.reason);
         }
     });
 };

-ginger.updateInterface = function(name, content, suc, err){
+ginger.updateInterface = function(name, content, suc, err) {
     $.ajax({
-        url : 'plugins/ginger/network/interfaces/' + encodeURIComponent(name),
-        type : 'PUT',
-        contentType : 'application/json',
-        dataType : 'json',
-        data : JSON.stringify(content),
+        url: 'plugins/ginger/network/interfaces/' + encodeURIComponent(name),
+        type: 'PUT',
+        contentType: 'application/json',
+        dataType: 'json',
+        data: JSON.stringify(content),
         success: suc,
         error: err || function(data) {
             wok.message.error(data.responseJSON.reason);
@@ -188,50 +188,50 @@ ginger.updateInterface = function(name, content, suc, err){

 ginger.enableInterface = function(name, status, suc, err) {
     wok.requestJSON({
-        url : "plugins/ginger/network/interfaces/" + name +
-              '/' + (status == "down" ? 'deactivate' : 'activate'),
-        type : 'POST',
-        contentType : 'application/json',
-        dataType : 'json',
-        success : suc,
-        error : err
+        url: "plugins/ginger/network/interfaces/" + name +
+            '/' + (status == "down" ? 'deactivate' : 'activate'),
+        type: 'POST',
+        contentType: 'application/json',
+        dataType: 'json',
+        success: suc,
+        error: err
     });
 };

 ginger.deleteInterface = function(name, suc, err) {
-  wok.requestJSON({
-      url : 'plugins/ginger/network/cfginterfaces/' + name,
-      type : 'DELETE',
-      contentType : 'application/json',
-      dataType : 'json',
-      success : suc,
-      error : err || function(data) {
-          wok.message.error(data.responseJSON.reason);
-      }
-  });
+    wok.requestJSON({
+        url: 'plugins/ginger/network/cfginterfaces/' + name,
+        type: 'DELETE',
+        contentType: 'application/json',
+        dataType: 'json',
+        success: suc,
+        error: err || function(data) {
+            wok.message.error(data.responseJSON.reason);
+        }
+    });
 };

-ginger.getNetworkGlobals = function(suc, err){
+ginger.getNetworkGlobals = function(suc, err) {
     wok.requestJSON({
-        url : 'plugins/ginger/network',
-        type : 'GET',
-        contentType : 'application/json',
-        dataType : 'json',
-        resend : true,
-        success : suc,
-        error : err || function(data) {
+        url: 'plugins/ginger/network',
+        type: 'GET',
+        contentType: 'application/json',
+        dataType: 'json',
+        resend: true,
+        success: suc,
+        error: err || function(data) {
             wok.message.error(data.responseJSON.reason);
         }
     });
 };

-ginger.updateNetworkGlobals = function(content, suc, err){
+ginger.updateNetworkGlobals = function(content, suc, err) {
     $.ajax({
-        url : 'plugins/ginger/network',
-        type : 'PUT',
-        contentType : 'application/json',
-        dataType : 'json',
-        data : JSON.stringify(content),
+        url: 'plugins/ginger/network',
+        type: 'PUT',
+        contentType: 'application/json',
+        dataType: 'json',
+        data: JSON.stringify(content),
         success: suc,
         error: err || function(data) {
             wok.message.error(data.responseJSON.reason);
@@ -241,12 +241,12 @@ ginger.updateNetworkGlobals = function(content, suc, err){

 ginger.confirmNetworkUpdate = function(suc, err) {
     wok.requestJSON({
-        url : 'plugins/ginger/network/confirm_change',
-        type : 'POST',
-        contentType : 'application/json',
-        dataType : 'json',
-        success : suc,
-        error : err || function(data) {
+        url: 'plugins/ginger/network/confirm_change',
+        type: 'POST',
+        contentType: 'application/json',
+        dataType: 'json',
+        success: suc,
+        error: err || function(data) {
             wok.message.error(data.responseJSON.reason);
         }
     });
@@ -254,55 +254,57 @@ ginger.confirmNetworkUpdate = function(suc, err) {

 ginger.confirmInterfaceUpdate = function(name, suc, err) {
     wok.requestJSON({
-        url : 'plugins/ginger/network/interfaces/' + encodeURIComponent(name) + '/confirm_change',
-        type : 'POST',
-        contentType : 'application/json',
-        dataType : 'json',
-        success : suc,
-        error : err || function(data) {
+        url: 'plugins/ginger/network/interfaces/' + encodeURIComponent(name) + '/confirm_change',
+        type: 'POST',
+        contentType: 'application/json',
+        dataType: 'json',
+        success: suc,
+        error: err || function(data) {
             wok.message.error(data.responseJSON.reason);
         }
     });
 };

-ginger.validateIp = function(ip){
+ginger.validateIp = function(ip) {
     var ipReg = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
     return ipReg.test(ip);
 };

-ginger.validateMask = function(mask){
-    if(mask.indexOf('.')!=-1){
+ginger.validateMask = function(mask) {
+    if (mask.indexOf('.') != -1) {
         var secs = mask.split('.');
         var binMask = "";
-        for(var i=0; i<secs.length; i++)
+        for (var i = 0; i < secs.length; i++)
             binMask += parseInt(secs[i]).toString(2);
         return /^1+0+$/.test(binMask);
-    }else{
+    } else {
         return mask > 0 && mask < 32;
     }
 };

-ginger.getPowerProfiles = function(suc, err){
+ginger.getPowerProfiles = function(suc, err) {
     wok.requestJSON({
-        url : 'plugins/ginger/powerprofiles',
-        type : 'GET',
-        contentType : 'application/json',
-        dataType : 'json',
-        resend : true,
-        success : suc,
-        error : err || function(data) {
+        url: 'plugins/ginger/powerprofiles',
+        type: 'GET',
+        contentType: 'application/json',
+        dataType: 'json',
+        resend: true,
+        success: suc,
+        error: err || function(data) {
             wok.message.error(data.responseJSON.reason);
         }
     });
 };

-ginger.activatePowerProfile = function(name, suc, err){
+ginger.activatePowerProfile = function(name, suc, err) {
     $.ajax({
-        url : "plugins/ginger/powerprofiles/" + encodeURIComponent(name),
-        type : 'PUT',
-        contentType : 'application/json',
-        dataType : 'json',
-        data : JSON.stringify({ active: true }),
+        url: "plugins/ginger/powerprofiles/" + encodeURIComponent(name),
+        type: 'PUT',
+        contentType: 'application/json',
+        dataType: 'json',
+        data: JSON.stringify({
+            active: true
+        }),
         success: suc,
         error: err || function(data) {
             wok.message.error(data.responseJSON.reason);
@@ -310,113 +312,113 @@ ginger.activatePowerProfile = function(name, suc, err){
     });
 };

-ginger.getSANAdapters = function(suc, err){
+ginger.getSANAdapters = function(suc, err) {
     wok.requestJSON({
-        url : 'plugins/ginger/san_adapters',
-        type : 'GET',
-        contentType : 'application/json',
-        dataType : 'json',
-        resend : true,
-        success : suc,
-        error : err || function(data) {
+        url: 'plugins/ginger/san_adapters',
+        type: 'GET',
+        contentType: 'application/json',
+        dataType: 'json',
+        resend: true,
+        success: suc,
+        error: err || function(data) {
             wok.message.error(data.responseJSON.reason);
         }
     });
 };

-ginger.getSensors = function(suc, err){
+ginger.getSensors = function(suc, err) {
     wok.requestJSON({
-        url : 'plugins/ginger/sensors',
-        type : 'GET',
-        contentType : 'application/json',
-        dataType : 'json',
-        resend : true,
-        success : suc,
-        error : err || function(data) {
+        url: 'plugins/ginger/sensors',
+        type: 'GET',
+        contentType: 'application/json',
+        dataType: 'json',
+        resend: true,
+        success: suc,
+        error: err || function(data) {
             wok.message.error(data.responseJSON.reason);
         }
     });
 };

-ginger.getSEPSubscriptions = function(suc, err){
+ginger.getSEPSubscriptions = function(suc, err) {
     wok.requestJSON({
-        url : 'plugins/ginger/ibm_sep',
-        type : 'GET',
-        contentType : 'application/json',
-        dataType : 'json',
-        resend : true,
-        success : suc,
-        error : err || function(data) {
+        url: 'plugins/ginger/ibm_sep',
+        type: 'GET',
+        contentType: 'application/json',
+        dataType: 'json',
+        resend: true,
+        success: suc,
+        error: err || function(data) {
             wok.message.error(data.responseJSON.reason);
         }
     });
 };

-ginger.deleteSubscription = function (hostname, suc, err) {
+ginger.deleteSubscription = function(hostname, suc, err) {
     wok.requestJSON({
-        url : wok.url + 'plugins/ginger/ibm_sep/subscribers/' + hostname,
-        type : 'DELETE',
-        contentType : 'application/json',
-        dataType : 'json',
-        success : suc,
-        error : err || function(data) {
+        url: wok.url + 'plugins/ginger/ibm_sep/subscribers/' + hostname,
+        type: 'DELETE',
+        contentType: 'application/json',
+        dataType: 'json',
+        success: suc,
+        error: err || function(data) {
             wok.message.error(data.responseJSON.reason);
         }
     });
 }

-ginger.addSEPSubscription = function(subscription, suc, err){
+ginger.addSEPSubscription = function(subscription, suc, err) {
     wok.requestJSON({
-        url : wok.url + 'plugins/ginger/ibm_sep/subscribers',
-        type : 'POST',
-        contentType : 'application/json',
-        dataType : 'json',
-        data : JSON.stringify(subscription),
-        resend : true,
-        success : suc,
-        error : err || function(data) {
+        url: wok.url + 'plugins/ginger/ibm_sep/subscribers',
+        type: 'POST',
+        contentType: 'application/json',
+        dataType: 'json',
+        data: JSON.stringify(subscription),
+        resend: true,
+        success: suc,
+        error: err || function(data) {
             wok.message.error(data.responseJSON.reason);
         }
     });
 };

-ginger.getSEPStatus = function(suc, err){
+ginger.getSEPStatus = function(suc, err) {
     wok.requestJSON({
-        url : 'plugins/ginger/ibm_sep',
-        type : 'GET',
-        contentType : 'application/json',
-        dataType : 'json',
-        resend : true,
-        success : suc,
-        error : err || function(data) {
+        url: 'plugins/ginger/ibm_sep',
+        type: 'GET',
+        contentType: 'application/json',
+        dataType: 'json',
+        resend: true,
+        success: suc,
+        error: err || function(data) {
             wok.message.error(data.responseJSON.reason);
         }
     });
 };

-ginger.startSEP = function(suc, err){
+ginger.startSEP = function(suc, err) {
     wok.requestJSON({
-        url : 'plugins/ginger/ibm_sep/start',
-        type : 'POST',
-        contentType : 'application/json',
-        dataType : 'json',
-        resend : true,
-        success : suc,
-        error : err || function(data) {
+        url: 'plugins/ginger/ibm_sep/start',
+        type: 'POST',
+        contentType: 'application/json',
+        dataType: 'json',
+        resend: true,
+        success: suc,
+        error: err || function(data) {
             wok.message.error(data.responseJSON.reason);
         }
     });
 };

-ginger.stopSEP = function(suc, err){
+ginger.stopSEP = function(suc, err) {
     wok.requestJSON({
-        url : 'plugins/ginger/ibm_sep/stop',
-        type : 'POST',
-        contentType : 'application/json',
-        dataType : 'json',
-        resend : true,
-        success : suc,
-        error : err || function(data) {
+        url: 'plugins/ginger/ibm_sep/stop',
+        type: 'POST',
+        contentType: 'application/json',
+        dataType: 'json',
+        resend: true,
+        success: suc,
+        error: err || function(data) {
             wok.message.error(data.responseJSON.reason);
         }
     });
@@ -424,13 +426,13 @@ ginger.stopSEP = function(suc, err){

 ginger.getUsers = function(suc, err) {
     wok.requestJSON({
-        url : 'plugins/ginger/users',
-        type : 'GET',
-        contentType : 'application/json',
-        dataType : 'json',
-        resend : true,
-        success : suc,
-        error : function(data) {
+        url: 'plugins/ginger/users',
+        type: 'GET',
+        contentType: 'application/json',
+        dataType: 'json',
+        resend: true,
+        success: suc,
+        error: function(data) {
             wok.message.error(data.responseJSON.reason);
         }
     });
@@ -438,27 +440,27 @@ ginger.getUsers = function(suc, err) {

 ginger.addUser = function(username, suc, err) {
     wok.requestJSON({
-        url : 'plugins/ginger/users',
-        type : 'POST',
-        contentType : 'application/json',
-        data : JSON.stringify(username),
-        dataType : 'json',
-        resend : true,
-        success : suc,
-        error :  err || function(data) {
-             wok.message.error(data.responseJSON.reason);
+        url: 'plugins/ginger/users',
+        type: 'POST',
+        contentType: 'application/json',
+        data: JSON.stringify(username),
+        dataType: 'json',
+        resend: true,
+        success: suc,
+        error: err || function(data) {
+            wok.message.error(data.responseJSON.reason);
         }
     });
 }

-ginger.deleteUser = function (username, suc, err) {
+ginger.deleteUser = function(username, suc, err) {
     wok.requestJSON({
-        url : 'plugins/ginger/users/' + username,
-        type : 'DELETE',
-        contentType : 'application/json',
-        dataType : 'json',
-        success : suc,
-        error : function(data) {
+        url: 'plugins/ginger/users/' + username,
+        type: 'DELETE',
+        contentType: 'application/json',
+        dataType: 'json',
+        success: suc,
+        error: function(data) {
             wok.message.error(data.responseJSON.reason);
         }
     });
@@ -466,12 +468,12 @@ ginger.deleteUser = function (username, suc, err) {

 ginger.getCapabilities = function(suc, err) {
     wok.requestJSON({
-        url : 'plugins/ginger/capabilities',
-        type : 'GET',
-        contentType : 'application/json',
-        dataType : 'json',
-        success : suc,
-        error : function(data) {
+        url: 'plugins/ginger/capabilities',
+        type: 'GET',
+        contentType: 'application/json',
+        dataType: 'json',
+        success: suc,
+        error: function(data) {
             wok.message.error(data.responseJSON.reason);
         }
     });
@@ -480,16 +482,16 @@ ginger.getCapabilities = function(suc, err) {
 /**
  * Get the host information.
  */
-ginger.getHostDetails = function (suc,err) {
-  wok.requestJSON({
-      url : 'plugins/gingerbase/host',
-      type : 'GET',
-      resend: true,
-      contentType : 'application/json',
-      dataType : 'json',
-      success : suc,
-      error: err
-  });
+ginger.getHostDetails = function(suc, err) {
+    wok.requestJSON({
+        url: 'plugins/gingerbase/host',
+        type: 'GET',
+        resend: true,
+        contentType: 'application/json',
+        dataType: 'json',
+        success: suc,
+        error: err
+    });
 }

 /**
@@ -497,89 +499,103 @@ ginger.getHostDetails = function (suc,err) {
  */
 ginger.getPlugins = function(suc, err) {
     wok.requestJSON({
-        url : 'plugins',
-        type : 'GET',
+        url: 'plugins',
+        type: 'GET',
         resend: true,
-        contentType : 'application/json',
-        dataType : 'json',
-        success : suc,
+        contentType: 'application/json',
+        dataType: 'json',
+        success: suc,
         error: err
     });
 };
-ginger.getFilesystems =  function(suc , err){
-       wok.requestJSON({
-        url : 'plugins/ginger/filesystems',
-        type : 'GET',
-        contentType : 'application/json',
-        dataType : 'json',
-        success : suc,
-        error : function(data) {
+ginger.getFilesystems = function(suc, err) {
+    wok.requestJSON({
+        url: 'plugins/ginger/filesystems',
+        type: 'GET',
+        contentType: 'application/json',
+        dataType: 'json',
+        success: suc,
+        error: function(data) {
             wok.message.error(data.responseJSON.reason);
         }
     });
 }
-ginger.getSwapdevices =  function(suc , err){
-       wok.requestJSON({
-        url : 'plugins/ginger/swaps',
-        type : 'GET',
-        contentType : 'application/json',
-        dataType : 'json',
-        success : suc,
-        error : function(data) {
+ginger.getSwapdevices = function(suc, err) {
+    wok.requestJSON({
+        url: 'plugins/ginger/swaps',
+        type: 'GET',
+        contentType: 'application/json',
+        dataType: 'json',
+        success: suc,
+        error: function(data) {
             wok.message.error(data.responseJSON.reason);
         }
     });
 }

-ginger.getVolumegroups =  function(suc , err){
-       wok.requestJSON({
-        url : 'plugins/ginger/vgs',
-        type : 'GET',
-        contentType : 'application/json',
-        dataType : 'json',
-        success : suc,
-        error : function(data) {
+ginger.getVolumegroups = function(suc, err) {
+    wok.requestJSON({
+        url: 'plugins/ginger/vgs',
+        type: 'GET',
+        contentType: 'application/json',
+        dataType: 'json',
+        success: suc,
+        error: function(data) {
+            wok.message.error(data.responseJSON.reason);
+        }
+    });
+}
+ginger.getStgdevs = function(suc, err) {
+    wok.requestJSON({
+        url: 'plugins/ginger/stgdevs',
+        type: 'GET',
+        contentType: 'application/json',
+        dataType: 'json',
+        success: suc,
+        error: function(data) {
             wok.message.error(data.responseJSON.reason);
         }
     });
 }
-ginger.getStgdevs =  function(suc , err){
+
+ginger.getFcpTapeDevices = function(suc, err) {
     wok.requestJSON({
-        url : 'plugins/ginger/stgdevs',
-        type : 'GET',
-        contentType : 'application/json',
-        dataType : 'json',
-        success : suc,
-        error : function(data) {
+        url: 'plugins/gingers390x/lstapes',
+        type: 'GET',
+        contentType: 'application/json',
+        dataType: 'json',
+        success: suc,
+        error: function(data) {
             wok.message.error(data.responseJSON.reason);
         }
     });
 }

-ginger.getFcpTapeDevices =  function(suc , err){
+ginger.getSysmodules = function(suc, err) {
     wok.requestJSON({
-        url : 'plugins/gingers390x/lstapes',
-        type : 'GET',
-        contentType : 'application/json',
-        dataType : 'json',
-        success : suc,
-        error : function(data) {
+        url: 'plugins/ginger/sysmodules',
+        type: 'GET',
+        contentType: 'application/json',
+        dataType: 'json',
+        success: suc,
+        error: function(data) {
             wok.message.error(data.responseJSON.reason);
         }
     });
 }
+
 ginger.formatDASDDevice = function(busId, settings, suc, err, progress) {
     var onResponse = function(data) {
-       taskID = data['id'];
-       ginger.trackTask(taskID, suc, err, progress);
+        taskID = data['id'];
+        ginger.trackTask(taskID, suc, err, progress);
     };

     wok.requestJSON({
-        url : '/plugins/ginger/dasddevs/'+busId+'/format',
-        type : 'POST',
-        contentType : 'application/json',
-        data : JSON.stringify(settings),
-        dataType : 'json',
+        url: '/plugins/ginger/dasddevs/' + busId + '/format',
+        type: 'POST',
+        contentType: 'application/json',
+        data: JSON.stringify(settings),
+        dataType: 'json',
         success: onResponse,
         error: err
     });
@@ -587,11 +603,11 @@ ginger.formatDASDDevice = function(busId, settings, suc, err, progress) {

 ginger.removeDASDDevice = function(busId, settings, suc, err, progress) {
     wok.requestJSON({
-        url : "/plugins/gingers390x/storagedevices/"+ busId +"/offline",
-        type : 'POST',
-        contentType : 'application/json',
-        data : JSON.stringify(settings),
-        dataType : 'json',
+        url: "/plugins/gingers390x/storagedevices/" + busId + "/offline",
+        type: 'POST',
+        contentType: 'application/json',
+        data: JSON.stringify(settings),
+        dataType: 'json',
         success: suc,
         error: err
     });
@@ -599,11 +615,22 @@ ginger.removeDASDDevice = function(busId, settings, suc, err, progress) {

 ginger.removeFCDevice = function(lunPath, settings, suc, err, progress) {
     wok.requestJSON({
-        url : "/plugins/gingers390x/fcluns/"+ lunPath,
-        type : 'DELETE',
-        contentType : 'application/json',
-        data : JSON.stringify(settings),
-        dataType : 'json',
+        url: "/plugins/gingers390x/fcluns/" + lunPath,
+        type: 'DELETE',
+        contentType: 'application/json',
+        data: JSON.stringify(settings),
+        dataType: 'json',
+        success: suc,
+        error: err
+    });
+}
+
+ginger.removeSysmodule = function(moduleId, suc, err) {
+    wok.requestJSON({
+        url: 'plugins/ginger/sysmodules/' + moduleId,
+        type: 'DELETE',
+        contentType: 'application/json',
+        dataType: 'json',
         success: suc,
         error: err
     });
@@ -611,45 +638,45 @@ ginger.removeFCDevice = function(lunPath, settings, suc, err, progress) {

 ginger.getTask = function(taskId, suc, err) {
     wok.requestJSON({
-        url : 'plugins/ginger/tasks/' + encodeURIComponent(taskId),
-        type : 'GET',
-        contentType : 'application/json',
-        dataType : 'json',
-        success : suc,
-        error : err
+        url: 'plugins/ginger/tasks/' + encodeURIComponent(taskId),
+        type: 'GET',
+        contentType: 'application/json',
+        dataType: 'json',
+        success: suc,
+        error: err
     });
 }
 ginger.trackTask = function(taskID, suc, err, progress) {
     var onTaskResponse = function(result) {
         var taskStatus = result['status'];
-        switch(taskStatus) {
-        case 'running':
-            progress && progress(result);
-            setTimeout(function() {
-                ginger.trackTask(taskID, suc, err, progress);
-            }, 2000);
-            break;
-        case 'finished':
-            suc && suc(result);
-            break;
-        case 'failed':
-            err && err(result);
-            break;
-        default:
-            break;
+        switch (taskStatus) {
+            case 'running':
+                progress && progress(result);
+                setTimeout(function() {
+                    ginger.trackTask(taskID, suc, err, progress);
+                }, 2000);
+                break;
+            case 'finished':
+                suc && suc(result);
+                break;
+            case 'failed':
+                err && err(result);
+                break;
+            default:
+                break;
         }
     };

     ginger.getTask(taskID, onTaskResponse, err);
-    if(trackingTasks.indexOf(taskID) < 0)
+    if (trackingTasks.indexOf(taskID) < 0)
         trackingTasks.push(taskID);
 }

-ginger.trackdevices = function(trackDevicelist,removeItem) {
+ginger.trackdevices = function(trackDevicelist, removeItem) {
     "use strict";
     trackDevicelist = jQuery.grep(trackDevicelist, function(value) {
-          return value != removeItem;
-        });
+        return value != removeItem;
+    });
     return trackDevicelist;
 };

@@ -657,17 +684,17 @@ ginger.trackdevices = function(trackDevicelist,removeItem) {
  * Create a network interface with new information.
  */
 ginger.createCfgInterface = function(settings, suc, err) {
-  wok.requestJSON({
-    url: 'plugins/ginger/network/cfginterfaces/',
-    type: 'POST',
-    contentType: 'application/json',
-    data: JSON.stringify(settings),
-    dataType: 'json',
-    success: suc,
-    error: err || function(data) {
-      wok.message.error(data.responseJSON.reason);
-    }
-  });
+    wok.requestJSON({
+        url: 'plugins/ginger/network/cfginterfaces/',
+        type: 'POST',
+        contentType: 'application/json',
+        data: JSON.stringify(settings),
+        dataType: 'json',
+        success: suc,
+        error: err || function(data) {
+            wok.message.error(data.responseJSON.reason);
+        }
+    });
 }

 /**
@@ -678,74 +705,74 @@ ginger.createCfgInterface = function(settings, suc, err) {
  * @param err callback for error
  */
 ginger.listCfgInterface = function(suc, err) {
-    wok.requestJSON({
-      url: 'plugins/ginger/network/cfginterfaces/',
-      type: 'GET',
-      contentType: 'application/json',
-      dataType: 'json',
-      success: suc,
-      error: err
-    });
-}
-/**
- * Retrieve the information of a given network interface by its name from it's cfg file.
- *
- * @param interface name
- * @param suc callback for success
- * @param err callback for error
- */
+        wok.requestJSON({
+            url: 'plugins/ginger/network/cfginterfaces/',
+            type: 'GET',
+            contentType: 'application/json',
+            dataType: 'json',
+            success: suc,
+            error: err
+        });
+    }
+    /**
+     * Retrieve the information of a given network interface by its name from it's cfg file.
+     *
+     * @param interface name
+     * @param suc callback for success
+     * @param err callback for error
+     */
 ginger.retrieveCfgInterface = function(interface, suc, err) {
+        wok.requestJSON({
+            url: 'plugins/ginger/network/cfginterfaces/' + interface,
+            type: 'GET',
+            contentType: 'application/json',
+            dataType: 'json',
+            success: suc,
+            error: err
+        });
+    }
+    /**
+     * Update a network interface with new information.
+     */
+ginger.updateCfgInterface = function(interface, settings, suc, err) {
     wok.requestJSON({
-      url: 'plugins/ginger/network/cfginterfaces/'+interface,
-      type: 'GET',
-      contentType: 'application/json',
-      dataType: 'json',
-      success: suc,
-      error: err
+        url: 'plugins/ginger/network/cfginterfaces/' + encodeURIComponent(interface),
+        type: 'PUT',
+        contentType: 'application/json',
+        data: JSON.stringify(settings),
+        dataType: 'json',
+        success: suc,
+        error: err
     });
 }
-  /**
-   * Update a network interface with new information.
-   */
-ginger.updateCfgInterface = function(interface, settings, suc, err) {
-  wok.requestJSON({
-    url: 'plugins/ginger/network/cfginterfaces/' + encodeURIComponent(interface),
-    type: 'PUT',
-    contentType: 'application/json',
-    data: JSON.stringify(settings),
-    dataType: 'json',
-    success: suc,
-    error: err
-  });
-}

-ginger.disableclass =  function(clas){
-  jQuery("."+clas).css('pointer-events', 'none')
-  jQuery("."+clas).find("input, select, button, textarea, div").attr("disabled",true);
-  jQuery("."+clas).css('opacity', '0.5')
+ginger.disableclass = function(clas) {
+    jQuery("." + clas).css('pointer-events', 'none')
+    jQuery("." + clas).find("input, select, button, textarea, div").attr("disabled", true);
+    jQuery("." + clas).css('opacity', '0.5')
 }

-ginger.enableclass =  function(clas){
-  jQuery("."+clas).css('pointer-events', 'auto')
-  jQuery("."+clas).find("input, select, button, textarea, div").attr("disabled",false);
-  jQuery("."+clas).css('opacity', 'initial')
+ginger.enableclass = function(clas) {
+    jQuery("." + clas).css('pointer-events', 'auto')
+    jQuery("." + clas).find("input, select, button, textarea, div").attr("disabled", false);
+    jQuery("." + clas).css('opacity', 'initial')
 }

 ginger.isInteger = function(value) {
-return !isNaN(value) &&
-       parseInt(Number(value)) == value &&
-       !isNaN(parseInt(value, 10));
+    return !isNaN(value) &&
+        parseInt(Number(value)) == value &&
+        !isNaN(parseInt(value, 10));
 }

 ginger.isValidIPv6 = function(ipv6addr) {
-  if (/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$|^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$|^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/.test(ipv6addr)) {
-      return true;
-  } else {
-      return false;
-  }
-  return false;
+    if (/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$|^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$|^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/.test(ipv6addr)) {
+        return true;
+    } else {
+        return false;
+    }
+    return false;
 }

 ginger.isValidIPv6Prefix = function(prefix) {
-  return prefix > 0 && prefix < 127;
-}
+    return prefix > 0 && prefix < 127;
+}
\ No newline at end of file
diff --git a/ui/pages/tabs/host-sysmodules.html.tmpl b/ui/pages/tabs/host-sysmodules.html.tmpl
new file mode 100644
index 0000000..d7225de
--- /dev/null
+++ b/ui/pages/tabs/host-sysmodules.html.tmpl
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<!--
+Copyright IBM Corp, 2016
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+-->
+#unicode UTF-8
+#import gettext
+#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang)
+#silent _ = t.gettext
+#silent _t = t.gettext
+<html>
+<head>
+<link rel="stylesheet" type="text/css" href="plugins/ginger/css/ginger.css">
+<script type="text/javascript" src="plugins/ginger/js/util.js"></script>
+<script type="text/javascript" src="plugins/ginger/js/host-sysmodules.js"></script>
+<script type="text/javascript" src="plugins/ginger/js/ginger-bootgrid.js"></script>
+</head>
+<body>
+    <div id="host-sysmodules-root-container" class="ginger">
+        <nav class="navbar navbar-default toolbar">
+            <div class="container">
+                <div id="toolbar"></div>
+            </div>
+        </nav>
+        <div class="container">
+            <div id="alert-container"></div>
+            <div id="gingerHostAdmin" class="host-admin">
+                <div class="panel-group accordion" id="sysmodules-accordion" role="tablist" aria-multiselectable="true">
+                     <h3>
+                        <a role="button" data-toggle="collapse" data-parent="#sysmodules-accordion" href="#sysmodules-content-area" aria-expanded="false" aria-controls="sysmodules-content-area" class="">
+                            <span class="accordion-icon"></span><span class="accordion-text">$_("System Modules Management")</span>
+                        </a>
+                    </h3>
+                    <div id="sysmodules-content-area" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne">
+                         <div class="sysmodules-actions btn-group" id="sysmodules-actions-
+                         area">
+                            <button class="btn btn-primary actBtn load-modules-btn" type="submit" data-toggle="modal" data-target="#loadModule"><i class="fa fa-download"></i> $_("Load Modules")</button>
+                         </div>
+                         <div class="wok-datagrid" id="sysmodules-datagrid">
+                            <div class="wok-datagrid-header">
+                                <span class="column-name">$_("Name")</span><!--
+                                --><span class="column-depends">$_("Depends On")</span><!--
+                                --><span class="column-version">$_("Version")</span><!--
+                                --><span class="column-details">$_("Details")</span><!--
+                                --><span class="column-actions" style="display:none">
+                                    <span class="sr-only">Actions</span><!--
+                                --></span>
+                            </div>
+                            <ul class="wok-datagrid-body" id="sysmodules-body"></ul>
+                         </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+<script id="sysmodulesItem" type="html/text">
+    <li class="wok-datagrid-row in" name="sysmodulesBodyItem" id="{name}">
+        <span class="column-name" title="{name}">{name}</span><!--
+        --><span class="column-depends">{depends}</span><!--
+        --><span class="column-version">{version}</span><!--
+        --><span class="column-details">
+            <div class="arrow arrow-down"></div>
+        </span><!--
+        --><span class="column-actions btn btn-link btn-unload"><i class="fa fa-upload"></i> $_("Unload")</span>
+        <div class="sysmodules-details" style="display: none;">
+            <div class="details-list" ></div>
+        </div>
+        <div class="clear"></div>
+    </li>
+</script>
+<script>
+    ginger.initSysmodules();
+</script>
+</body>
+</html>
--
1.8.3.1




--

André Teodoro