[activemq-artemis] branch master updated: ARTEMIS-2541 Improve message browser of Admin UI

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[activemq-artemis] branch master updated: ARTEMIS-2541 Improve message browser of Admin UI

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

clebertsuconic pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/activemq-artemis.git


The following commit(s) were added to refs/heads/master by this push:
     new 54daa44  ARTEMIS-2541 Improve message browser of Admin UI
     new 7a8234c  This closes #2886
54daa44 is described below

commit 54daa445ed70e3efddd6d08ab055d6e9065634be
Author: sebthom <[hidden email]>
AuthorDate: Fri Nov 8 12:31:50 2019 +0100

    ARTEMIS-2541 Improve message browser of Admin UI
---
 .../src/main/webapp/plugin/css/activemq.css        |   4 +
 .../src/main/webapp/plugin/js/browse.js            | 105 ++++++++++++++++++---
 .../impl/openmbean/CompositeDataConstants.java     |   2 +
 .../management/impl/openmbean/OpenTypeSupport.java |  15 +--
 4 files changed, 106 insertions(+), 20 deletions(-)

diff --git a/artemis-hawtio/activemq-branding/src/main/webapp/plugin/css/activemq.css b/artemis-hawtio/activemq-branding/src/main/webapp/plugin/css/activemq.css
index ab78f10..edc1583 100644
--- a/artemis-hawtio/activemq-branding/src/main/webapp/plugin/css/activemq.css
+++ b/artemis-hawtio/activemq-branding/src/main/webapp/plugin/css/activemq.css
@@ -2139,6 +2139,10 @@ li.dropdown.open > a.dropdown-toggle {
   color: #ffffff !important;
 }
 
+.ngRow:hover {
+  background-color: lightyellow;
+}
+
 .ngRow.selected {
   color: #ffffff !important;
   background-color: #B21054 !important;
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/browse.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/browse.js
index 769f00f..d8185c6 100644
--- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/browse.js
+++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/browse.js
@@ -26,44 +26,58 @@ var ARTEMIS = (function(ARTEMIS) {
          displayName: 'Message ID',
          cellTemplate: '<div class="ngCellText"><a ng-click="openMessageDialog(row)">{{row.entity.messageID}}</a></div>',
          // for ng-grid
-         width: '10%'
-      }, {
-         field: 'userID',
-         displayName: 'User ID',
-         width: '10%'
+         width: '100px'
       }, {
          field: 'type',
          displayName: 'Type',
-         width: '10%'
+         cellTemplate: '<div class="ngCellText" title="{{row.entity.type}}">{{formatType(row.entity.type)}}</div>',
+         width: '90px'
       }, {
          field: 'durable',
          displayName: 'Durable',
-         width: '10%'
+         width: '70px'
       }, {
          field: 'priority',
          displayName: 'Priority',
-         width: '7%'
+         width: '70px'
       }, {
          field: 'timestamp',
          displayName: 'Timestamp',
-         width: '19%'
+         cellTemplate: '<div class="ngCellText" title="{{row.entity.timestamp}}">{{formatTimestamp(row.entity.timestamp)}}</div>',
+         width: '160px'
       }, {
          field: 'expiration',
          displayName: 'Expires',
-         width: '10%'
+         cellTemplate: '<div class="ngCellText" title="{{row.entity.expiration}}">{{formatExpires(row.entity.expiration)}}</div>',
+         width: '160px'
       }, {
          field: 'redelivered',
          displayName: 'Redelivered',
-         width: '10%'
+         width: '100px'
       }, {
          field: 'largeMessage',
          displayName: 'Large',
-         width: '10%'
+         width: '50px'
+      }, {
+         field: 'persistentSize',
+         displayName: 'Persistent Size',
+         cellTemplate: '<div class="ngCellText" title="{{row.entity.persistentSize.toLocaleString()}} bytes">{{formatPersistentSize(row.entity.persistentSize)}}</div>',
+         width: '120px'
+      }, {
+         field: 'userID',
+         displayName: 'User ID',
+         width: '15%'
+      }, {
+         displayName: 'Validated User',
+         cellTemplate: '<div class="ngCellText">{{row.entity.StringProperties._AMQ_VALIDATED_USER}}</div>',
+         width: '*'
       }];
+
       var attributes = defaultAttributes;
       if (sessionStorage.getItem('browseColumnDefs')) {
          attributes = JSON.parse(sessionStorage.getItem('browseColumnDefs'));
       }
+
       $scope.$on('ngGridEventColumns', function(newColumns) {
          ARTEMIS.log.debug('ngGridEventColumns:', newColumns);
          var visibles = newColumns.targetScope.columns.reduce(function(visibles, column) {
@@ -76,6 +90,7 @@ var ARTEMIS = (function(ARTEMIS) {
          });
          sessionStorage.setItem('browseColumnDefs', JSON.stringify(attributes));
       });
+
       $scope.pagingOptions = {
          pageSizes: [50, 100, 200],
          pageSize: 100,
@@ -113,8 +128,10 @@ var ARTEMIS = (function(ARTEMIS) {
          afterSelectionChange: afterSelectionChange
       };
       $scope.showMessageDetails = false;
+
       var ignoreColumns = ["PropertiesText", "BodyPreview", "text"];
       var flattenColumns = ["BooleanProperties", "ByteProperties", "ShortProperties", "IntProperties", "LongProperties", "FloatProperties", "DoubleProperties", "StringProperties"];
+
       $scope.$watch('workspace.selection', function() {
          if (workspace.moveIfViewInvalid()) {
             return;
@@ -143,6 +160,61 @@ var ARTEMIS = (function(ARTEMIS) {
       };
       $scope.refresh = loadTable;
       ARTEMIS.decorate($scope);
+
+      var MS_PER_SEC  = 1000;
+      var MS_PER_MIN  = 60 * MS_PER_SEC;
+      var MS_PER_HOUR = 60 * MS_PER_MIN;
+      var MS_PER_DAY  = 24 * MS_PER_HOUR;
+
+      function pad2(value) {
+         return (value < 10 ? '0' : '') + value;
+      }
+
+      $scope.formatExpires = function(timestamp) {
+         if (isNaN(timestamp)) {
+            return timestamp;
+         }
+         var expiresIn = timestamp - Date.now();
+         if (Math.abs(expiresIn) < MS_PER_DAY) {
+            var duration = expiresIn < 0 ? -expiresIn : expiresIn;
+            var hours = pad2(Math.floor((duration / MS_PER_HOUR) % 24));
+            var mins  = pad2(Math.floor((duration / MS_PER_MIN) % 60));
+            var secs  = pad2(Math.floor((duration / MS_PER_SEC) % 60));
+            if (expiresIn < 0) {
+               // "HH:mm:ss ago"
+               return hours + ":" + mins + ":" + secs + " ago";
+            }
+            // "in HH:mm:ss ago"
+            return "in " + hours + ":" + mins + ":" + secs;
+         }
+         return $scope.formatTimestamp(timestamp);
+      }
+
+      $scope.formatTimestamp = function(timestamp) {
+         if (isNaN(timestamp)) {
+            return timestamp;
+         }
+         var d = new Date(timestamp);
+         // "yyyy-MM-dd HH:mm:ss"
+         return d.getFullYear() + "-" + pad2(d.getMonth()) + "-" + pad2(d.getDay()) + " " + pad2(d.getHours()) + ":" + pad2(d.getMinutes()) + ":" + pad2(d.getSeconds());
+      }
+
+      var typeLabels = ["default", "1", "object", "text", "bytes", "map", "stream", "embedded"];
+      $scope.formatType = function(type) {
+         if (isNaN(type)) {
+            return type;
+         }
+         return type > -1 && type < 8 ? typeLabels[type] : type
+      }
+
+      $scope.formatPersistentSize = function(bytes) {
+         if(isNaN(bytes) || bytes < 0) return "n/a";
+         if(bytes < 10240) return bytes.toLocaleString() + " Bytes";
+         if(bytes < 1048576) return (bytes / 1024).toFixed(2) + " KB";
+         if(bytes < 1073741824) return (bytes / 1048576).toFixed(2) + " MB";
+         return (bytes / 1073741824).toFixed(2) + " GB";
+      }
+
       $scope.moveMessages = function() {
          var selection = workspace.selection;
          var mbean = selection.objectName;
@@ -212,6 +284,7 @@ var ARTEMIS = (function(ARTEMIS) {
             return [];
          }
       };
+
       function populateTable(response) {
          var data = response.value;
          ARTEMIS.log.info("loading data:" + data);
@@ -237,7 +310,6 @@ var ARTEMIS = (function(ARTEMIS) {
        * just create the HTML in code :)
        */
       function createBodyText(message) {
-
          ARTEMIS.log.info("loading message:" + message);
          if (message.text) {
             var body = message.text;
@@ -320,6 +392,11 @@ var ARTEMIS = (function(ARTEMIS) {
             if (value === null) {
                value = '';
             }
+            if (key == "expiration" || key == "timestamp") {
+               value = $scope.formatTimestamp(value) + " (" + value + ")";
+            } else if (key == "type") {
+               value = $scope.formatType(value) + " (" + value + ")";
+            }
             buffer.push('<tr><td class="propertyName"><span class="green">Header</span> - ' + key + '</td><td class="property-value">' + value + '</td></tr>');
          }
 
@@ -384,7 +461,7 @@ var ARTEMIS = (function(ARTEMIS) {
             } else {
                onDlq(false);
             }
-            jolokia.request({ type: 'exec', mbean: objName, operation: 'countMessages()'}, onSuccess(function(response) {$scope.totalServerItems = response.value;}));
+            jolokia.request({ type: 'exec', mbean: objName, operation: 'countMessages()'}, onSuccess(function(response) { $scope.totalServerItems = response.value; }));
             jolokia.request({ type: 'exec', mbean: objName, operation: 'browse(int, int)', arguments: [$scope.pagingOptions.currentPage, $scope.pagingOptions.pageSize] }, onSuccess(populateTable));
          }
       }
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/openmbean/CompositeDataConstants.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/openmbean/CompositeDataConstants.java
index feae788..a8cde03 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/openmbean/CompositeDataConstants.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/openmbean/CompositeDataConstants.java
@@ -30,6 +30,7 @@ public interface CompositeDataConstants {
    String BODY = "BodyPreview";
    String TEXT_BODY = "text";
    String LARGE_MESSAGE = "largeMessage";
+   String PERSISTENT_SIZE = "persistentSize";
    String PROPERTIES = "PropertiesText";
 
    String ADDRESS_DESCRIPTION = "The Address";
@@ -43,6 +44,7 @@ public interface CompositeDataConstants {
    String TIMESTAMP_DESCRIPTION = "The message timestamp";
    String BODY_DESCRIPTION = "The message body";
    String LARGE_MESSAGE_DESCRIPTION = "Is the message treated as a large message";
+   String PERSISTENT_SIZE_DESCRIPTION = "The message size when persisted on disk";
    String PROPERTIES_DESCRIPTION = "The properties text";
 
    // User properties
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/openmbean/OpenTypeSupport.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/openmbean/OpenTypeSupport.java
index c19be9c..dfd8ce3 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/openmbean/OpenTypeSupport.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/openmbean/OpenTypeSupport.java
@@ -26,15 +26,13 @@ import javax.management.openmbean.SimpleType;
 import javax.management.openmbean.TabularDataSupport;
 import javax.management.openmbean.TabularType;
 import java.io.IOException;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 import org.apache.activemq.artemis.api.core.ActiveMQBuffer;
+import org.apache.activemq.artemis.api.core.ActiveMQException;
 import org.apache.activemq.artemis.api.core.ICoreMessage;
 import org.apache.activemq.artemis.api.core.Message;
 import org.apache.activemq.artemis.api.core.SimpleString;
@@ -107,8 +105,9 @@ public final class OpenTypeSupport {
          addItem(CompositeDataConstants.EXPIRATION, CompositeDataConstants.EXPIRATION_DESCRIPTION, SimpleType.LONG);
          addItem(CompositeDataConstants.PRIORITY, CompositeDataConstants.PRIORITY_DESCRIPTION, SimpleType.BYTE);
          addItem(CompositeDataConstants.REDELIVERED, CompositeDataConstants.REDELIVERED_DESCRIPTION, SimpleType.BOOLEAN);
-         addItem(CompositeDataConstants.TIMESTAMP, CompositeDataConstants.TIMESTAMP_DESCRIPTION, SimpleType.STRING);
+         addItem(CompositeDataConstants.TIMESTAMP, CompositeDataConstants.TIMESTAMP_DESCRIPTION, SimpleType.LONG);
          addItem(CompositeDataConstants.LARGE_MESSAGE, CompositeDataConstants.LARGE_MESSAGE_DESCRIPTION, SimpleType.BOOLEAN);
+         addItem(CompositeDataConstants.PERSISTENT_SIZE, CompositeDataConstants.PERSISTENT_SIZE_DESCRIPTION, SimpleType.LONG);
 
          addItem(CompositeDataConstants.PROPERTIES, CompositeDataConstants.PROPERTIES_DESCRIPTION, SimpleType.STRING);
 
@@ -145,11 +144,15 @@ public final class OpenTypeSupport {
          rc.put(CompositeDataConstants.TYPE, m.getType());
          rc.put(CompositeDataConstants.DURABLE, m.isDurable());
          rc.put(CompositeDataConstants.EXPIRATION, m.getExpiration());
-         DateFormat dateFormat = new SimpleDateFormat();
-         rc.put(CompositeDataConstants.TIMESTAMP, dateFormat.format(new Date(m.getTimestamp())));
+         rc.put(CompositeDataConstants.TIMESTAMP, m.getTimestamp());
          rc.put(CompositeDataConstants.PRIORITY, m.getPriority());
          rc.put(CompositeDataConstants.REDELIVERED, ref.getDeliveryCount() > 1);
          rc.put(CompositeDataConstants.LARGE_MESSAGE, m.isLargeMessage());
+         try {
+            rc.put(CompositeDataConstants.PERSISTENT_SIZE, m.getPersistentSize());
+         } catch (final ActiveMQException e1) {
+            rc.put(CompositeDataConstants.PERSISTENT_SIZE, -1);
+         }
 
          Map<String, Object> propertyMap = m.toPropertyMap();