You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ro...@apache.org on 2017/12/21 09:58:15 UTC

[cloudstack] 06/24: CLOUDSTACK-10129: UX improvements and event timeline

This is an automated email from the ASF dual-hosted git repository.

rohit pushed a commit to branch debian9-systemvmtemplate
in repository https://gitbox.apache.org/repos/asf/cloudstack.git

commit 4a10f7ab61fe74ef2d42441e233adc6d53e6deb4
Author: Rohit Yadav <ro...@shapeblue.com>
AuthorDate: Tue Nov 28 19:25:09 2017 +0530

    CLOUDSTACK-10129: UX improvements and event timeline
    
    - Fixes timezone issue where dates show up as nvalid in UI
    - Introduces new event timeline listing/filtering of events
    - Several UI improvements to add columns in list views
    - Bulk operations support in instance list view to shutdown and destroy
      multiple-selected VMs (limitation: after operation, redundant entries
      may show up in the list view, refreshing VM list view fixes that)
    - Align table thead/tbody to avoid splitting of tables
    
    Signed-off-by: Rohit Yadav <ro...@shapeblue.com>
---
 .../org/apache/cloudstack/api/ApiConstants.java    |   2 +
 .../api/command/user/event/ListEventsCmd.java      |   7 +
 .../cloudstack/api/response/EventResponse.java     |   2 +-
 .../schema/src/com/cloud/user/UserAccountVO.java   |   4 +
 engine/schema/src/com/cloud/user/UserVO.java       |   4 +
 .../src/com/cloud/api/query/QueryManagerImpl.java  |  10 +-
 ui/css/cloudstack3.css                             |   3 +-
 ui/l10n/en.js                                      |   3 +
 ui/scripts/events.js                               |  20 +-
 ui/scripts/instances.js                            | 275 ++++++++++++---------
 ui/scripts/metrics.js                              |  13 +-
 ui/scripts/network.js                              |  51 +++-
 ui/scripts/sharedFunctions.js                      |   2 +-
 ui/scripts/storage.js                              |  30 ++-
 ui/scripts/system.js                               | 112 +++++++--
 ui/scripts/templates.js                            |  27 ++
 ui/scripts/ui/widgets/dataTable.js                 |  13 +-
 17 files changed, 412 insertions(+), 166 deletions(-)

diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java
index a5bd95f..89deeef 100644
--- a/api/src/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/org/apache/cloudstack/api/ApiConstants.java
@@ -205,6 +205,7 @@ public class ApiConstants {
     public static final String OUTOFBANDMANAGEMENT_POWERSTATE = "outofbandmanagementpowerstate";
     public static final String OUTOFBANDMANAGEMENT_ENABLED = "outofbandmanagementenabled";
     public static final String PARAMS = "params";
+    public static final String PARENT_ID = "parentid";
     public static final String PARENT_DOMAIN_ID = "parentdomainid";
     public static final String PASSWORD = "password";
     public static final String SHOULD_UPDATE_PASSWORD = "update_passwd_on_host";
@@ -274,6 +275,7 @@ public class ApiConstants {
     public static final String SNAPSHOT_QUIESCEVM = "quiescevm";
     public static final String SOURCE_ZONE_ID = "sourcezoneid";
     public static final String START_DATE = "startdate";
+    public static final String START_ID = "startid";
     public static final String START_IP = "startip";
     public static final String START_IPV6 = "startipv6";
     public static final String START_PORT = "startport";
diff --git a/api/src/org/apache/cloudstack/api/command/user/event/ListEventsCmd.java b/api/src/org/apache/cloudstack/api/command/user/event/ListEventsCmd.java
index a4934fa..b98c308 100644
--- a/api/src/org/apache/cloudstack/api/command/user/event/ListEventsCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/event/ListEventsCmd.java
@@ -65,6 +65,9 @@ public class ListEventsCmd extends BaseListProjectAndAccountResourcesCmd {
     @Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, description = "the event type (see event types)")
     private String type;
 
+    @Parameter(name = ApiConstants.START_ID, type = CommandType.UUID, entityType = EventResponse.class, description = "the parent/start ID of the event, when provided this will list all the events with the start/parent ID including the parent event")
+    private Long startId;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -97,6 +100,10 @@ public class ListEventsCmd extends BaseListProjectAndAccountResourcesCmd {
         return type;
     }
 
+    public Long getStartId() {
+        return startId;
+    }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
diff --git a/api/src/org/apache/cloudstack/api/response/EventResponse.java b/api/src/org/apache/cloudstack/api/response/EventResponse.java
index 5ce66ed..da15434 100644
--- a/api/src/org/apache/cloudstack/api/response/EventResponse.java
+++ b/api/src/org/apache/cloudstack/api/response/EventResponse.java
@@ -78,7 +78,7 @@ public class EventResponse extends BaseResponse implements ControlledViewEntityR
     @Param(description = "the state of the event")
     private Event.State state;
 
-    @SerializedName("parentid")
+    @SerializedName(ApiConstants.PARENT_ID)
     @Param(description = "whether the event is parented")
     private String parentId;
 
diff --git a/engine/schema/src/com/cloud/user/UserAccountVO.java b/engine/schema/src/com/cloud/user/UserAccountVO.java
index 5ce0eb7..2ad2ae0 100644
--- a/engine/schema/src/com/cloud/user/UserAccountVO.java
+++ b/engine/schema/src/com/cloud/user/UserAccountVO.java
@@ -33,6 +33,7 @@ import org.apache.cloudstack.api.InternalIdentity;
 
 import com.cloud.utils.db.Encrypt;
 import com.cloud.utils.db.GenericDao;
+import com.google.common.base.Strings;
 
 @Entity
 @Table(name = "user")
@@ -257,6 +258,9 @@ public class UserAccountVO implements UserAccount, InternalIdentity {
 
     @Override
     public String getTimezone() {
+        if (Strings.isNullOrEmpty(timezone)) {
+            return "UTC";
+        }
         return timezone;
     }
 
diff --git a/engine/schema/src/com/cloud/user/UserVO.java b/engine/schema/src/com/cloud/user/UserVO.java
index da7811e..d6ddb58 100644
--- a/engine/schema/src/com/cloud/user/UserVO.java
+++ b/engine/schema/src/com/cloud/user/UserVO.java
@@ -34,6 +34,7 @@ import org.apache.cloudstack.api.InternalIdentity;
 import com.cloud.user.Account.State;
 import com.cloud.utils.db.Encrypt;
 import com.cloud.utils.db.GenericDao;
+import com.google.common.base.Strings;
 
 /**
  * A bean representing a user
@@ -233,6 +234,9 @@ public class UserVO implements User, Identity, InternalIdentity {
 
     @Override
     public String getTimezone() {
+        if (Strings.isNullOrEmpty(timezone)) {
+            return "UTC";
+        }
         return timezone;
     }
 
diff --git a/server/src/com/cloud/api/query/QueryManagerImpl.java b/server/src/com/cloud/api/query/QueryManagerImpl.java
index 42bef79..2a6919b 100644
--- a/server/src/com/cloud/api/query/QueryManagerImpl.java
+++ b/server/src/com/cloud/api/query/QueryManagerImpl.java
@@ -520,6 +520,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
         String keyword = cmd.getKeyword();
         Integer entryTime = cmd.getEntryTime();
         Integer duration = cmd.getDuration();
+        Long startId = cmd.getStartId();
 
         Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(
                 cmd.getDomainId(), cmd.isRecursive(), null);
@@ -542,7 +543,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
         sb.and("createDateG", sb.entity().getCreateDate(), SearchCriteria.Op.GTEQ);
         sb.and("createDateL", sb.entity().getCreateDate(), SearchCriteria.Op.LTEQ);
         sb.and("state", sb.entity().getState(), SearchCriteria.Op.NEQ);
-        sb.and("startId", sb.entity().getStartId(), SearchCriteria.Op.EQ);
+        sb.or("startId", sb.entity().getStartId(), SearchCriteria.Op.EQ);
         sb.and("createDate", sb.entity().getCreateDate(), SearchCriteria.Op.BETWEEN);
         sb.and("displayEvent", sb.entity().getDisplay(), SearchCriteria.Op.EQ);
         sb.and("archived", sb.entity().getArchived(), SearchCriteria.Op.EQ);
@@ -561,6 +562,13 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
             sc.setParameters("id", id);
         }
 
+        if (startId != null) {
+            sc.setParameters("startId", startId);
+            if (id == null) {
+                sc.setParameters("id", startId);
+            }
+        }
+
         if (keyword != null) {
             SearchCriteria<EventJoinVO> ssc = _eventJoinDao.createSearchCriteria();
             ssc.addOr("type", SearchCriteria.Op.LIKE, "%" + keyword + "%");
diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css
index 987f35d..519778b 100644
--- a/ui/css/cloudstack3.css
+++ b/ui/css/cloudstack3.css
@@ -96,7 +96,7 @@ a:hover {
 
 /*Table*/
 table {
-  width: 940px;
+  width: 955px;
   max-width: 977px;
   margin: 15px 15px 12px 12px;
   font-size: 13px;
@@ -1307,7 +1307,6 @@ div.panel div.list-view {
 
 div.panel div.list-view div.data-table table {
   width: 955px;
-  margin-top: 44px;
 }
 
 .detail-view div.list-view div.data-table table {
diff --git a/ui/l10n/en.js b/ui/l10n/en.js
index 4476b6a..fe2e80f 100644
--- a/ui/l10n/en.js
+++ b/ui/l10n/en.js
@@ -558,6 +558,7 @@ var dictionary = {"ICMP.code":"ICMP Code",
 "label.console.proxy.vm":"Console Proxy VM",
 "label.continue":"Continue",
 "label.continue.basic.install":"Continue with basic installation",
+"label.control.ip":"Control IP",
 "label.copying.iso":"Copying ISO",
 "label.corrections.saved":"Corrections saved",
 "label.counter":"Counter",
@@ -751,6 +752,7 @@ var dictionary = {"ICMP.code":"ICMP Code",
 "label.event":"Event",
 "label.event.archived":"Event Archived",
 "label.event.deleted":"Event Deleted",
+"label.event.timeline":"Event Timeline",
 "label.every":"Every",
 "label.example":"Example",
 "label.expunge":"Expunge",
@@ -995,6 +997,7 @@ var dictionary = {"ICMP.code":"ICMP Code",
 "label.manage":"Manage",
 "label.manage.resources":"Manage Resources",
 "label.managed":"Managed",
+"label.managed.state":"Managed State",
 "label.management":"Management",
 "label.management.ips":"Management IP Addresses",
 "label.management.server":"Management Server",
diff --git a/ui/scripts/events.js b/ui/scripts/events.js
index 2fd70dd..82550a9 100644
--- a/ui/scripts/events.js
+++ b/ui/scripts/events.js
@@ -46,12 +46,12 @@
                             label: 'label.type',
                             truncate: true
                         },
-                        domain: {
-                            label: 'label.domain'
-                        },
                         account: {
                             label: 'label.account'
                         },
+                        domain: {
+                            label: 'label.domain'
+                        },
                         created: {
                             label: 'label.date',
                             converter: cloudStack.converters.toLocalDate
@@ -338,6 +338,14 @@
                         var data = {};
                         listViewDataProvider(args, data);
 
+                        if ("events" in args.context) {
+                            var startId = args.context.events[0].parentid;
+                            if (!startId) {
+                                startId = args.context.events[0].id;
+                            }
+                            data.startid = startId;
+                        }
+
                         $.ajax({
                             url: createURL('listEvents'),
                             data: data,
@@ -357,8 +365,12 @@
                     },
                     detailView: {
                         name: 'label.details',
-                        actions: {
+                        viewAll: {
+                            path: 'events',
+                            label: 'label.event.timeline',
+                        },
 
+                        actions: {
                             // Remove single event
                             remove: {
                                 label: 'label.delete',
diff --git a/ui/scripts/instances.js b/ui/scripts/instances.js
index db7f533..ab075b0 100644
--- a/ui/scripts/instances.js
+++ b/ui/scripts/instances.js
@@ -17,6 +17,153 @@
 (function($, cloudStack) {
     var vmMigrationHostObjs, ostypeObjs;
 
+    var vmStopAction = function(args) {
+        var action = {
+            messages: {
+                confirm: function(args) {
+                    return 'message.action.stop.instance';
+                },
+                notification: function(args) {
+                    return 'label.action.stop.instance';
+                }
+            },
+            label: 'label.action.stop.instance',
+            compactLabel: 'label.stop',
+            addRow: 'false',
+            createForm: {
+                title: 'notification.stop.instance',
+                desc: 'message.action.stop.instance',
+                fields: {
+                    forced: {
+                        label: 'force.stop',
+                        isBoolean: true,
+                        isChecked: false
+                    }
+                }
+            },
+            action: function(args) {
+                var instances = args.context.instances;
+                $(instances).map(function(index, instance) {
+                    var data = {
+                        id: instance.id,
+                        forced: (args.data.forced == "on")
+                    };
+                    $.ajax({
+                        url: createURL("stopVirtualMachine"),
+                        data: data,
+                        dataType: "json",
+                        success: function(json) {
+                            var jid = json.stopvirtualmachineresponse.jobid;
+                            args.response.success({
+                                _custom: {
+                                    jobId: jid,
+                                    getUpdatedItem: function(json) {
+                                        return $.extend(json.queryasyncjobresultresponse.jobresult.virtualmachine, { hostid: null });
+                                    },
+                                    getActionFilter: function() {
+                                        return vmActionfilter;
+                                    }
+                                }
+                            });
+                        },
+                        error: function(json) {
+                            args.response.error(parseXMLHttpResponse(json));
+                        }
+                    });
+                });
+            },
+            notification: {
+                poll: pollAsyncJobResult
+            }
+        };
+
+
+        if (args && args.listView) {
+            $.extend(action, {
+                isHeader: true,
+                isMultiSelectAction: true
+            });
+        }
+
+        return action;
+    };
+
+    var vmDestroyAction = function(args) {
+        var action = {
+            messages: {
+                notification: function(args) {
+                    return 'label.action.destroy.instance';
+                }
+            },
+            label: 'label.action.destroy.instance',
+            compactLabel: 'label.destroy',
+            addRow: 'false',
+            createForm: {
+                title: 'label.action.destroy.instance',
+                desc: 'label.action.destroy.instance',
+                isWarning: true,
+                preFilter: function(args) {
+                    if (! g_allowUserExpungeRecoverVm) {
+                        args.$form.find('.form-item[rel=expunge]').hide();
+                    }
+                },
+                fields: {
+                    expunge: {
+                        label: 'label.expunge',
+                        isBoolean: true,
+                        isChecked: false
+                    }
+                }
+            },
+            action: function(args) {
+                var instances = args.context.instances;
+                $(instances).map(function(index, instance) {
+                    var data = {
+                        id: instance.id
+                    };
+                    if (args.data.expunge == 'on') {
+                        $.extend(data, {
+                            expunge: true
+                        });
+                    }
+                    $.ajax({
+                        url: createURL('destroyVirtualMachine'),
+                        data: data,
+                        success: function(json) {
+                            var jid = json.destroyvirtualmachineresponse.jobid;
+                            args.response.success({
+                                _custom: {
+                                    jobId: jid,
+                                    getUpdatedItem: function(json) {
+                                        if ('virtualmachine' in json.queryasyncjobresultresponse.jobresult) //destroy without expunge
+                                            return json.queryasyncjobresultresponse.jobresult.virtualmachine;
+                                        else //destroy with expunge
+                                            return { 'toRemove': true };
+                                    },
+                                    getActionFilter: function() {
+                                        return vmActionfilter;
+                                    }
+                                }
+                            });
+                        }
+                    });
+                });
+            },
+            notification: {
+                poll: pollAsyncJobResult
+            }
+        };
+
+        if (args && args.listView) {
+            $.extend(action, {
+                isHeader: true,
+                isMultiSelectAction: true
+            });
+        }
+
+        return action;
+    };
+
     var vmSnapshotAction = function(args) {
         var action = {
             messages: {
@@ -162,6 +309,7 @@
                 var hiddenFields = [];
                 if (!isAdmin()) {
                     hiddenFields.push('instancename');
+                    hiddenFields.push('account');
                 }
                 return hiddenFields;
             },
@@ -180,16 +328,26 @@
                 ipaddress: {
                     label: 'label.ip.address'
                 },
+                account: {
+                    label: 'label.account'
+                },
                 zonename: {
                     label: 'label.zone.name'
                 },
                 state: {
-                    label: 'label.state',
+                    label: 'label.metrics.state',
+                    converter: function (str) {
+                        // For localization
+                        return str;
+                    },
                     indicator: {
                         'Running': 'on',
                         'Stopped': 'off',
+                        'Error': 'off',
                         'Destroyed': 'off',
-                        'Error': 'off'
+                        'Expunging': 'off',
+                        'Stopping': 'warning',
+                        'Shutdowned': 'warning'
                     }
                 }
             },
@@ -304,6 +462,8 @@
                         poll: pollAsyncJobResult
                     }
                 },
+                stop: vmStopAction({ listView: true}),
+                destroy: vmDestroyAction({ listView: true }),
                 snapshot: vmSnapshotAction({ listView: true }),
                 viewMetrics: {
                     label: 'label.metrics',
@@ -683,55 +843,7 @@
                             poll: pollAsyncJobResult
                         }
                     },
-                    stop: {
-                        label: 'label.action.stop.instance',
-                        compactLabel: 'label.stop',
-                        createForm: {
-                            title: 'notification.stop.instance',
-                            desc: 'message.action.stop.instance',
-                            fields: {
-                                forced: {
-                                    label: 'force.stop',
-                                    isBoolean: true,
-                                    isChecked: false
-                                }
-                            }
-                        },
-                        action: function(args) {
-                            var array1 = [];
-                            array1.push("&forced=" + (args.data.forced == "on"));
-                            $.ajax({
-                                url: createURL("stopVirtualMachine&id=" + args.context.instances[0].id + array1.join("")),
-                                dataType: "json",
-                                async: true,
-                                success: function(json) {
-                                    var jid = json.stopvirtualmachineresponse.jobid;
-                                    args.response.success({
-                                        _custom: {
-                                            jobId: jid,
-                                            getUpdatedItem: function(json) {
-                                                return $.extend(json.queryasyncjobresultresponse.jobresult.virtualmachine, { hostid: null });
-                                            },
-                                            getActionFilter: function() {
-                                                return vmActionfilter;
-                                            }
-                                        }
-                                    });
-                                }
-                            });
-                        },
-                        messages: {
-                            confirm: function(args) {
-                                return 'message.action.stop.instance';
-                            },
-                            notification: function(args) {
-                                return 'label.action.stop.instance';
-                            }
-                        },
-                        notification: {
-                            poll: pollAsyncJobResult
-                        }
-                    },
+                    stop: vmStopAction(),
                     restart: {
                         label: 'label.action.reboot.instance',
                         compactLabel: 'label.reboot',
@@ -775,66 +887,7 @@
                         }
                     },
                     snapshot: vmSnapshotAction(),
-                    destroy: {
-                        label: 'label.action.destroy.instance',
-                        compactLabel: 'label.destroy',
-                        createForm: {
-                            title: 'label.action.destroy.instance',
-                            desc: 'label.action.destroy.instance',
-                            isWarning: true,
-                            preFilter: function(args) {
-                                if (! g_allowUserExpungeRecoverVm) {
-                                    args.$form.find('.form-item[rel=expunge]').hide();
-                                }
-                            },
-                            fields: {
-                                expunge: {
-                                    label: 'label.expunge',
-                                    isBoolean: true,
-                                    isChecked: false
-                                }
-                            }
-                        },
-                        messages: {
-                            notification: function(args) {
-                                return 'label.action.destroy.instance';
-                            }
-                        },
-                        action: function(args) {
-                            var data = {
-                                id: args.context.instances[0].id
-                            };
-                            if (args.data.expunge == 'on') {
-                                $.extend(data, {
-                                    expunge: true
-                                });
-                            }
-                            $.ajax({
-                                url: createURL('destroyVirtualMachine'),
-                                data: data,
-                                success: function(json) {
-                                    var jid = json.destroyvirtualmachineresponse.jobid;
-                                    args.response.success({
-                                        _custom: {
-                                            jobId: jid,
-                                            getUpdatedItem: function(json) {
-                                                if ('virtualmachine' in json.queryasyncjobresultresponse.jobresult) //destroy without expunge
-                                                    return json.queryasyncjobresultresponse.jobresult.virtualmachine;
-                                                else //destroy with expunge
-                                                    return { 'toRemove': true };
-                                            },
-                                            getActionFilter: function() {
-                                                return vmActionfilter;
-                                            }
-                                        }
-                                    });
-                                }
-                            });
-                        },
-                        notification: {
-                            poll: pollAsyncJobResult
-                        }
-                    },
+                    destroy: vmDestroyAction(),
                     expunge: {
                         label: 'label.action.expunge.instance',
                         compactLabel: 'label.expunge',
diff --git a/ui/scripts/metrics.js b/ui/scripts/metrics.js
index bc73934..19d0118 100644
--- a/ui/scripts/metrics.js
+++ b/ui/scripts/metrics.js
@@ -293,8 +293,6 @@
                         'Disconnected': 'off',
                         'Removed': 'off',
                         'Error': 'off',
-                        'Connecting': 'transition',
-                        'Rebalancing': 'transition',
                         'Alert': 'warning'
                     },
                     compact: true
@@ -448,9 +446,7 @@
                         'Error': 'off',
                         'Destroyed': 'off',
                         'Expunging': 'off',
-                        'Stopping': 'transition',
-                        'Starting': 'transition',
-                        'Migrating': 'transition',
+                        'Stopping': 'warning',
                         'Shutdowned': 'warning'
                     },
                     compact: true
@@ -560,13 +556,12 @@
                         return str;
                     },
                     indicator: {
-                        'Allocated': 'transition',
-                        'Creating': 'transition',
+                        'Allocated': 'on',
                         'Ready': 'on',
                         'Destroy': 'off',
                         'Expunging': 'off',
                         'Migrating': 'warning',
-                        'UploadOp': 'transition',
+                        'UploadOp': 'warning',
                         'Snapshotting': 'warning',
                     },
                     compact: true
@@ -651,7 +646,7 @@
                                 'Down': 'off',
                                 'Removed': 'off',
                                 'ErrorInMaintenance': 'off',
-                                'PrepareForMaintenance': 'transition',
+                                'PrepareForMaintenance': 'warning',
                                 'CancelMaintenance': 'warning',
                                 'Maintenance': 'warning',
                             },
diff --git a/ui/scripts/network.js b/ui/scripts/network.js
index 9054a85..7765178 100644
--- a/ui/scripts/network.js
+++ b/ui/scripts/network.js
@@ -808,13 +808,16 @@
 
                     },
                     id: 'networks',
+                    preFilter: function(args) {
+                        if (isAdmin() || isDomainAdmin()) {
+                            return []
+                        }
+                        return ['account']
+                    },
                     fields: {
                         name: {
                             label: 'label.name'
                         },
-                        account: {
-                            label: 'label.account'
-                        },
                         type: {
                             label: 'label.type'
                         },
@@ -823,6 +826,27 @@
                         },
                         ip6cidr: {
                             label: 'label.ipv6.CIDR'
+                        },
+                        account: {
+                            label: 'label.account'
+                        },
+                        zonename: {
+                            label: 'label.zone'
+                        },
+                        state: {
+                            converter: function(str) {
+                                // For localization
+                                return str;
+                            },
+                            label: 'label.state',
+                            indicator: {
+                                'Allocated': 'on',
+                                'Released': 'off',
+                                'Destroy': 'off',
+                                'Shutdown': 'off',
+                                'Setup': 'warning',
+                                'Implemented': 'on'
+                            }
                         }
                     },
 
@@ -1635,11 +1659,14 @@
                                                     networkid: args.context.networks[0].id
                                                 },
                                                 dataType: 'json',
-                                                async: true,
+                                                async: false,
                                                 success: function(json) {
                                                     var response = json.listegressfirewallrulesresponse.firewallrule ?
                                                         json.listegressfirewallrulesresponse.firewallrule : [];
 
+                                                    if (response.length > 0) {
+                                                        isConfigRulesMsgShown = true;
+                                                    }
                                                     args.response.success({
                                                         data: $.map(response, function(rule) {
                                                             if (rule.protocol == 'all') {
@@ -1899,6 +1926,12 @@
                 listView: {
                     id: 'ipAddresses',
                     label: 'label.ips',
+                    preFilter: function(args) {
+                        if (isAdmin()) {
+                            return ['account']
+                        }
+                        return []
+                    },
                     fields: {
                         ipaddress: {
                             label: 'label.ips',
@@ -1910,12 +1943,18 @@
                                 return text;
                             }
                         },
-                        zonename: {
-                            label: 'label.zone'
+                        associatednetworkname: {
+                            label: 'label.network'
                         },
                         virtualmachinedisplayname: {
                             label: 'label.vm.name'
                         },
+                        account: {
+                            label: 'label.account'
+                        },
+                        zonename: {
+                            label: 'label.zone'
+                        },
                         state: {
                             converter: function(str) {
                                 // For localization
diff --git a/ui/scripts/sharedFunctions.js b/ui/scripts/sharedFunctions.js
index c58ce05..606fed4 100644
--- a/ui/scripts/sharedFunctions.js
+++ b/ui/scripts/sharedFunctions.js
@@ -1285,7 +1285,7 @@ cloudStack.converters = {
             var disconnected = new Date();
             disconnected.setISO8601(UtcDate);
 
-            if (g_timezoneoffset != null) {
+            if (g_timezoneoffset != null && g_timezoneoffset != "null") {
                 localDate = disconnected.getTimePlusTimezoneOffset(g_timezoneoffset);
             } else {
                 var browserDate = new Date();
diff --git a/ui/scripts/storage.js b/ui/scripts/storage.js
index 9c017b1..1cba750 100644
--- a/ui/scripts/storage.js
+++ b/ui/scripts/storage.js
@@ -36,8 +36,10 @@
                     label: 'label.volumes',
                     preFilter: function(args) {
                         var hiddenFields = [];
-                        if (isAdmin() != true)
+                        if (isAdmin() != true) {
                             hiddenFields.push('hypervisor');
+                            hiddenFields.push('account');
+                        }
                         return hiddenFields;
                     },
                     fields: {
@@ -47,11 +49,33 @@
                         type: {
                             label: 'label.type'
                         },
+                        vmdisplayname: {
+                            label: 'label.vm.display.name'
+                        },
                         hypervisor: {
                             label: 'label.hypervisor'
                         },
-                        vmdisplayname: {
-                            label: 'label.vm.display.name'
+                        account: {
+                            label: 'label.account'
+                        },
+                        zonename: {
+                            label: 'label.zone'
+                        },
+                        state: {
+                            label: 'label.metrics.state',
+                            converter: function (str) {
+                                // For localization
+                                return str;
+                            },
+                            indicator: {
+                                'Allocated': 'on',
+                                'Ready': 'on',
+                                'Destroy': 'off',
+                                'Expunging': 'off',
+                                'Migrating': 'warning',
+                                'UploadOp': 'warning',
+                                'Snapshotting': 'warning',
+                            }
                         }
                     },
 
diff --git a/ui/scripts/system.js b/ui/scripts/system.js
index 256ed1c..9e80e27 100755
--- a/ui/scripts/system.js
+++ b/ui/scripts/system.js
@@ -39,7 +39,7 @@
             router.guestnetworkname = router.vpcname;
         }
 
-        if ("isredundantrouter" in router && router.isredundantrouter) {
+        if (router.isredundantrouter) {
             router.guestnetworkname = router.guestnetworkname + " (" + router.redundantstate + ")";
         }
 
@@ -2180,6 +2180,12 @@
                         },
                         isolationmethods: {
                             label: 'label.isolation.method'
+                        },
+                        vlan: {
+                            label: 'label.vlan'
+                        },
+                        broadcastdomainrange: {
+                            label: 'label.broadcast.domain.range'
                         }
                     },
 
@@ -9205,6 +9211,14 @@
                                         data: data,
                                         success: function (json) {
                                             var systemvmObjs = json.listsystemvmsresponse.systemvm;
+                                            $(systemvmObjs).each(function(idx, item) {
+                                                var controlIp = item.linklocalip;
+                                                if (item.hypervisor == "VMware") {
+                                                    var controlIp = item.privateip;
+                                                }
+                                                item.controlip = controlIp;
+                                            });
+
                                             if (systemvmObjs != undefined) {
                                                 $.ajax({
                                                     url: createURL('listHosts'),
@@ -9585,16 +9599,19 @@
                                     label: 'label.name'
                                 },
                                 publicip: {
-                                    label: 'label.public.ip'
+                                    label: 'label.ip'
                                 },
-                                account: {
-                                    label: 'label.account'
+                                routerType: {
+                                    label: 'label.type'
                                 },
                                 guestnetworkname: {
                                     label: 'label.network'
                                 },
-                                routerType: {
-                                    label: 'label.type'
+                                account: {
+                                    label: 'label.account'
+                                },
+                                hostname: {
+                                    label: 'label.host'
                                 },
                                 state: {
                                     converter: function (str) {
@@ -10976,6 +10993,12 @@
                                 return args;
                             }
                         },
+                        controlip: {
+                            label: 'label.control.ip'
+                        },
+                        hostname: {
+                            label: 'label.host'
+                        },
                         zonename: {
                             label: 'label.zone'
                         },
@@ -13293,12 +13316,19 @@
                         netmask: {
                             label: 'label.netmask'
                         },
+                        zonename: {
+                            label: 'label.zone'
+                        },
                         allocationstate: {
                             converter: function (str) {
                                 // For localization
                                 return str;
                             },
-                            label: 'label.allocation.state'
+                            label: 'label.allocation.state',
+                            indicator: {
+                                'Enabled': 'on',
+                                'Disabled': 'off'
+                            }
                         }
                     },
 
@@ -13934,23 +13964,27 @@
                         name: {
                             label: 'label.name'
                         },
+                        hypervisortype: {
+                            label: 'label.hypervisor'
+                        },
+                        zonename: {
+                            label: 'label.zone'
+                        },
                         podname: {
                             label: 'label.pod'
                         },
-                        hypervisortype: {
-                            label: 'label.hypervisor'
+                        managedstate: {
+                            label: 'label.managed.state'
                         },
-                        //allocationstate: { label: 'label.allocation.state' },
-                        //managedstate: { label: 'Managed State' },
                         allocationstate: {
                             converter: function (str) {
                                 // For localization
                                 return str;
                             },
-                            label: 'label.state',
+                            label: 'label.allocation.state',
                             indicator: {
                                 'Enabled': 'on',
-                                'Destroyed': 'off'
+                                'Disabled': 'off'
                             }
                         }
                     },
@@ -15487,15 +15521,26 @@
                         name: {
                             label: 'label.name'
                         },
+                        ipaddress: {
+                            label: 'label.ip.address'
+                        },
+                        hypervisor: {
+                            label: 'label.hypervisor'
+                        },
                         zonename: {
                             label: 'label.zone'
                         },
-                        podname: {
-                            label: 'label.pod'
-                        },
                         clustername: {
                             label: 'label.cluster'
                         },
+                        resourcestate: {
+                            label: 'label.resource.state',
+                            indicator: {
+                                'Enabled': 'on',
+                                'Disabled': 'off',
+                                'Maintenance': 'warning'
+                            }
+                        },
                         state: {
                             label: 'label.state',
                             indicator: {
@@ -17497,12 +17542,34 @@
                             label: 'label.path',
                             truncate: true
                         },
+                        type: {
+                            label: 'label.type'
+                        },
+                        scope: {
+                            label: 'label.scope'
+                        },
                         clustername: {
                             label: 'label.cluster',
                             truncate: true
                         },
-                        scope: {
-                            label: 'label.scope'
+                        zonename: {
+                            label: 'label.zone'
+                        },
+                        state: {
+                            label: 'label.state',
+                            converter: function (str) {
+                                // For localization
+                                return str;
+                            },
+                            indicator: {
+                                'Up': 'on',
+                                'Down': 'off',
+                                'Removed': 'off',
+                                'ErrorInMaintenance': 'off',
+                                'PrepareForMaintenance': 'warning',
+                                'CancelMaintenance': 'warning',
+                                'Maintenance': 'warning',
+                            }
                         }
                     },
 
@@ -19492,8 +19559,17 @@
                                 name: {
                                     label: 'label.name'
                                 },
+                                url: {
+                                    label: 'label.url'
+                                },
                                 protocol: {
                                     label: 'label.protocol'
+                                },
+                                scope: {
+                                    label: 'label.scope'
+                                },
+                                zonename: {
+                                    label: 'label.zone'
                                 }
                             },
 
diff --git a/ui/scripts/templates.js b/ui/scripts/templates.js
index 1ab1b9b..b2df73e 100755
--- a/ui/scripts/templates.js
+++ b/ui/scripts/templates.js
@@ -55,12 +55,24 @@
                             label: 'label.community'
                         }
                     },
+                    preFilter: function() {
+                        if (isAdmin()||isDomainAdmin()) {
+                            return []
+                        }
+                        return ['account']
+                    },
                     fields: {
                         name: {
                             label: 'label.name'
                         },
                         hypervisor: {
                             label: 'label.hypervisor'
+                        },
+                        ostypename: {
+                            label: 'label.os.type'
+                        },
+                        account: {
+                            label: 'label.account'
                         }
                     },
 
@@ -2038,9 +2050,21 @@
                             label: 'label.community'
                         }
                     },
+                    preFilter: function() {
+                        if (isAdmin()||isDomainAdmin()) {
+                            return []
+                        }
+                        return ['account']
+                    },
                     fields: {
                         name: {
                             label: 'label.name'
+                        },
+                        ostypename: {
+                            label: 'label.os.type'
+                        },
+                        account: {
+                            label: 'label.account'
                         }
                     },
 
@@ -2347,7 +2371,10 @@
                                             id: item.id,
                                             name: item.name,
                                             description: item.description,
+                                            ostypename: item.ostypename,
                                             ostypeid: item.ostypeid,
+                                            account: item.account,
+                                            domain: item.domain,
                                             zones: item.zonename,
                                             zoneids: [item.zoneid]
                                         };
diff --git a/ui/scripts/ui/widgets/dataTable.js b/ui/scripts/ui/widgets/dataTable.js
index 4574052..216487f 100644
--- a/ui/scripts/ui/widgets/dataTable.js
+++ b/ui/scripts/ui/widgets/dataTable.js
@@ -78,19 +78,12 @@
             return true;
         };
 
-        var splitTable = function() {
+        var reattachTable = function() {
             var $mainContainer = $('<div>')
                 .addClass('data-table')
                 .appendTo($table.parent())
-                .append(
-                    $table.detach()
+                .append($table.detach()
             );
-            $table = $mainContainer;
-            var $theadContainer = $('<div>').addClass('fixed-header').prependTo($table);
-            var $theadTable = $('<table>').appendTo($theadContainer).attr('nowrap', 'nowrap');
-            var $thead = $table.find('thead').detach().appendTo($theadTable);
-
-            return $thead;
         };
 
         /**
@@ -289,7 +282,7 @@
         var init = function() {
             var noSelect = options && options.noSelect == true ? true : false;
             if (!$table.closest('div.data-table').size() && !$table.hasClass('no-split')) {
-                splitTable();
+                reattachTable();
                 $table.find('tbody').closest('table').addClass('body');
             }
 

-- 
To stop receiving notification emails like this one, please contact
"commits@cloudstack.apache.org" <co...@cloudstack.apache.org>.