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 <[email protected]>
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();