commit e66439fe49b63f0a0d6025cd1e6d399bc3706583
parent ce29b09ca58f787eab73fd028efe8634e7708598
Author: Felicitus <felicitus@felicitus.org>
Date: Mon, 13 Jul 2015 19:59:19 +0200
Refactored the exception dialog to accept exceptions of the type PartKeepr.data.HydraException
Diffstat:
3 files changed, 297 insertions(+), 214 deletions(-)
diff --git a/src/PartKeepr/FrontendBundle/Resources/public/js/Data/HydraException.js b/src/PartKeepr/FrontendBundle/Resources/public/js/Data/HydraException.js
@@ -0,0 +1,42 @@
+/**
+ * Represents a hydra exception.
+ *
+ * @class
+ */
+Ext.define('PartKeepr.data.HydraException', {
+ config: {
+ /**
+ * @cfg {String} description
+ * The description of the exception
+ */
+ description: undefined,
+
+ /**
+ * @cfg {String} title
+ * The title of the exception
+ */
+ title: undefined,
+
+ /**
+ * @cfg {Array} trace
+ * The trace of the exception
+ */
+ trace: []
+ },
+
+ /**
+ * Creates the HydraException object.
+ * @param {Object} [config] Config object.
+ */
+ constructor: function(config) {
+ if (config["hydra:description"]) {
+ config.description = config["hydra:description"];
+ }
+
+ if (config["hydra:title"]) {
+ config.title = config["hydra:title"];
+ }
+
+ this.initConfig(config);
+ }
+});+
\ No newline at end of file
diff --git a/src/PartKeepr/FrontendBundle/Resources/public/js/Dialogs/ExceptionWindow.js b/src/PartKeepr/FrontendBundle/Resources/public/js/Dialogs/ExceptionWindow.js
@@ -9,241 +9,279 @@ Ext.define('PartKeepr.ExceptionWindow', {
width: 500,
autoHeight: true,
maxHeight: 800,
+ constrain: true,
cls: Ext.baseCSSPrefix + 'message-box',
-
- initComponent: function () {
-
- this.iconComponent = Ext.create('Ext.Component', {
- cls: 'ext-mb-icon',
- width: 40,
- height: 35,
- style: {
- 'float': 'left'
- }
+
+ initComponent: function ()
+ {
+ this.iconComponent = Ext.create('Ext.Component', {
+ baseCls: Ext.baseCSSPrefix + 'message-box-icon' + " " + Ext.baseCSSPrefix + 'message-box-error'
});
-
- this.messageDiv = Ext.create('Ext.Component', { autoEl: { tag: 'div' },
+
+ this.messageDiv = Ext.create('Ext.Component', {
+ autoEl: {tag: 'div'},
cls: 'ext-mb-text',
- style: 'margin-left: 40px;'
+ height: 20
});
-
- this.detailDiv = Ext.create('Ext.Component', { autoEl: { tag: 'div' },
+
+ this.detailDiv = Ext.create('Ext.Component', {
+ flex: 1,
+ autoEl: {tag: 'div'},
cls: 'ext-mb-text',
- style: 'margin-left: 40px; margin-top: 20px;'
+ style: 'margin-top: 20px;overflow: auto;'
+ });
+
+ this.backtraceDetails = Ext.create('Ext.tree.Panel', {
+ rootVisible: false
});
-
- this.exceptionDetails = Ext.create('Ext.form.field.TextArea', {
- fieldLabel: i18n("Exception Details"),
- flex: 1,
- minHeight: 65,
- readOnly: true
+
+ this.requestDetails = Ext.create('Ext.form.field.TextArea', {
+ fieldLabel: i18n("Request"),
+ height: 65,
+ minHeight: 65,
+ readOnly: true
});
- this.backtraceDetails = Ext.create('Ext.form.field.TextArea', {
- fieldLabel: i18n("Backtrace"),
- flex: 1,
- minHeight: 65,
- readOnly: true
- });
-
- this.requestDetails = Ext.create('Ext.form.field.TextArea', {
- fieldLabel: i18n("Request"),
- flex: 1,
- minHeight: 65,
- readOnly: true
+ this.responseDetails = Ext.create('Ext.form.field.TextArea', {
+ fieldLabel: i18n("Response"),
+ height: 65,
+ minHeight: 65,
+ readOnly: true
});
-
- this.responseDetails = Ext.create('Ext.form.field.TextArea', {
- fieldLabel: i18n("Response"),
- flex: 1,
- minHeight: 65,
- readOnly: true
+
+ this.basicTab = Ext.create("Ext.panel.Panel", {
+ style: 'padding: 10px;',
+ layout: {
+ type: 'hbox',
+ align: 'stretch'
+ },
+ title: i18n("Basic"),
+ items: [
+ this.iconComponent,
+ {
+ border: false,
+ flex: 1,
+ layout: {
+ type: 'vbox',
+ align: 'stretch'
+ },
+
+ items: [this.messageDiv, this.detailDiv]
+ }
+ ]
});
-
- this.basicTab = Ext.create("Ext.panel.Panel", {
- style: 'padding: 10px',
- layout: 'anchor',
- anchor: '100% 100%',
- title: i18n("Basic"),
- items: [this.iconComponent, this.messageDiv, this.detailDiv ]
- });
-
- this.detailTab = Ext.create("Ext.form.Panel", {
- style: 'padding: 10px',
- layout: 'anchor',
- autoScroll: true,
- title: i18n("Detail"),
- items: [{
- xtype: 'panel',
- height: 300,
- border: false,
- layout: {
- type: 'vbox',
- align : 'stretch',
- pack : 'start'
- },
- items: [ this.exceptionDetails, this.backtraceDetails, this.requestDetails, this.responseDetails ]
- }]
- });
-
- this.fullReport = Ext.create("Ext.form.field.TextArea", {
- readOnly: true,
- height: 300
- });
-
- this.backtraceTab = Ext.create("Ext.panel.Panel", {
- style: 'padding: 10px',
- layout: 'fit',
- anchor: '100% 100%',
- title: i18n("Full Report"),
- items: [ this.fullReport ]
- });
-
- this.topContainer = Ext.create("Ext.tab.Panel", {
- items: [ this.basicTab, this.detailTab, this.backtraceTab ]
- });
-
- this.items = this.topContainer;
-
- this.dockedItems = [{
- xtype: 'toolbar',
- dock: 'bottom',
- ui: 'footer',
- defaults: {minWidth: 80},
+
+ this.detailTab = Ext.create("Ext.form.Panel", {
+ style: 'padding: 10px;',
+ height: 300,
+ width: 500,
layout: {
- pack: 'center'
+ type: 'vbox',
+ align: 'stretch'
},
+ title: i18n("Detail"),
items: [
- { xtype: 'button', text: 'OK', handler: Ext.bind(function () { this.hide(); }, this) }
+ this.requestDetails,
+ this.responseDetails,
+ {
+ xtype: 'fieldcontainer',
+ layout: "fit",
+ fieldLabel: i18n("Backtrace"),
+ flex: 1,
+ minHeight: 65,
+ readOnly: true,
+ items: this.backtraceDetails
+ }
]
- }];
-
- this.callParent();
-
+
+ });
+
+ this.fullReport = Ext.create("Ext.form.field.TextArea", {
+ readOnly: true,
+ height: 300
+ });
+
+ this.backtraceTab = Ext.create("Ext.panel.Panel", {
+ style: 'padding: 10px',
+ layout: 'fit',
+ anchor: '100% 100%',
+ title: i18n("Full Report"),
+ items: [this.fullReport]
+ });
+
+ this.topContainer = Ext.create("Ext.tab.Panel", {
+ layout: "fit",
+ items: [this.basicTab, this.detailTab, this.backtraceTab]
+ });
+
+ this.items = this.topContainer;
+
+ this.dockedItems = [
+ {
+ xtype: 'toolbar',
+ dock: 'bottom',
+ ui: 'footer',
+ defaults: {minWidth: 80},
+ layout: {
+ pack: 'center'
+ },
+ items: [
+ {
+ xtype: 'button', text: 'OK', handler: Ext.bind(function ()
+ {
+ this.hide();
+ }, this)
+ }
+ ]
+ }
+ ];
+
+ this.callParent();
+
},
- setIcon : function(icon) {
- this.iconComponent.removeCls(this.iconCls);
-
- if (icon) {
- this.iconComponent.show();
- this.iconComponent.addCls(Ext.baseCSSPrefix + 'dlg-icon');
- this.iconComponent.addCls(icon);
+ /**
+ * Private. Updates the exception dialog with the exception data.
+ *
+ * @see showException
+ *
+ * @param {PartKeepr.data.HydraException} exception The exception data
+ * @param {Object} response The response data
+ */
+ _showException: function (exception, response)
+ {
+ var separator = "==================================";
+
+ this.messageDiv.update('<strong>' + exception.getTitle() + '</strong>');
+ this.setTitle(exception.getTitle());
+
+ var fullDetails = exception.getTitle();
+
+ if (exception.getDescription()) {
+ fullDetails += "\n\n" + i18n("Details") + "\n" + separator + "\n";
+ fullDetails += exception.getDescription();
+
+ this.detailDiv.update(exception.getDescription());
+ } else {
+ this.detailDiv.update("");
+ }
+
+ if (exception.getTrace()) {
+ var traceData = this.convertTraceToTree(exception.getTrace());
+
+ var store = Ext.create("Ext.data.TreeStore", {
+ root: traceData
+ });
+
+ this.backtraceDetails.setStore(store);
+ }
+
+ if (!response.request) {
+ response.request = {};
+ }
+
+ var requestData;
+
+ if (response.request && response.request.options && response.request.options.method && response.request.options.url) {
+ requestData = response.request.options.method + " " + response.request.options.url;
} else {
- this.iconComponent.removeCls(Ext.baseCSSPrefix + 'dlg-icon');
- this.iconComponent.hide();
+ requestData = "";
+ }
+
+ if (response.request.jsonData) {
+ requestData += "\n\n" + response.request.jsonData;
+ }
+
+ fullDetails += "\n\n" + i18n("Request") + "\n" + separator + "\n";
+ fullDetails += requestData;
+
+ this.requestDetails.setValue(nl2br(requestData));
+
+ fullDetails += "\n\n" + i18n("Response") + "\n" + separator + "\n";
+ fullDetails += response.responseText;
+
+ this.responseDetails.setValue(nl2br(response.responseText));
+
+ fullDetails += "\n\n" + i18n("Server Configuration") + "\n" + separator + "\n";
+
+ for (var j in window.parameters) {
+ fullDetails += j + ": " + window.parameters[j] + "\n";
}
+
+ this.fullReport.setValue(fullDetails);
+
+ this.show();
+ this.topContainer.layout.setActiveItem(0);
+
+ var keyMap = this.getKeyMap();
+ keyMap.on(Ext.event.Event.ENTER, function ()
+ {
+ this.hide();
+ }, this);
},
/**
- * Private. Updates the exception dialog with the exception data.
- *
- * @see showException
- *
- * @param exception The exception data
- * @param requestData The request data. May be empty.
+ * Recursively converts a trace to an ExtJS tree
+ *
+ * @param {Object} node The current node to process
+ * @param {String} prefixText A text to prefix the data with. If undefined, uses the type of the given node
+ * @return {Object} An object comptable with {Ext.data.NodeInterface}
*/
- _showException: function (exception, response) {
- var separator = "==================================";
-
- this.setIcon(Ext.MessageBox.ERROR);
-
- this.messageDiv.update(exception.message);
- this.setTitle(exception.message);
-
- var fullDetails = exception.message;
-
- if (exception.detail) {
- fullDetails += "\n\n"+i18n("Details")+"\n"+separator+"\n";
- fullDetails += exception.detail;
-
- this.detailDiv.update(exception.detail);
- } else {
- this.detailDiv.update("");
- }
-
-
- if (exception.exception) {
- fullDetails += "\n\n"+i18n("Exception")+"\n"+separator+"\n";
- fullDetails += exception.exception;
-
- this.exceptionDetails.setValue(exception.exception);
- } else {
- this.exceptionDetails.setValue("No information available");
- }
-
- if (exception.backtrace) {
- fullDetails += "\n\n"+i18n("Backtrace")+"\n"+separator+"\n";
- fullDetails += exception.exception;
-
- this.backtraceDetails.setValue(nl2br(exception.backtrace));
- } else {
- this.backtraceDetails.setValue("No backtrace available");
- }
-
- if (!response.request) {
- response.request = {};
- }
-
- if (response.request && response.request.options && response.request.options.method && response.request.options.url) {
- var requestData = response.request.options.method + " " + response.request.options.url;
- } else {
- var requestData = "";
- }
-
- if (response.request.jsonData) {
- requestData += "\n\n"+response.request.jsonData;
- }
-
- fullDetails += "\n\n"+i18n("Request")+"\n"+separator+"\n";
- fullDetails += requestData;
-
- this.requestDetails.setValue(nl2br(requestData));
-
- fullDetails += "\n\n"+i18n("Response")+"\n"+separator+"\n";
- fullDetails += response.responseText;
-
- this.responseDetails.setValue(nl2br(response.responseText));
-
- fullDetails += "\n\n"+i18n("Server Configuration")+"\n"+separator+"\n";
-
- for (var j in window.parameters) {
- fullDetails += j+": " + window.parameters[j]+"\n";
- }
-
- this.fullReport.setValue(fullDetails);
-
- this.show();
- this.topContainer.layout.setActiveItem(0);
-
- var keyMap = this.getKeyMap();
- keyMap.on(Ext.event.Event.ENTER, function () { this.hide(); }, this);
+ convertTraceToTree: function (node, prefixText)
+ {
+ if (!Ext.isDefined(prefixText)) {
+ prefixText = typeof node;
+ }
+
+ var treeNode = {
+ text: prefixText
+ };
+
+
+ if (Ext.isArray(node)) {
+ treeNode.children = [];
+ for (var j = 0; j < node.length; j++) {
+ treeNode.children.push(this.convertTraceToTree(node[j], j));
+ }
+
+ if (treeNode.children.length === 0) {
+ treeNode.leaf = true;
+ }
+ return treeNode;
+ }
+
+ if (Ext.isObject(node)) {
+ treeNode.children = [];
+
+ for (var property in node) {
+ treeNode.children.push(this.convertTraceToTree(node[property], property));
+ }
+
+ if (treeNode.children.length === 0) {
+ treeNode.leaf = true;
+ }
+
+ return treeNode;
+ }
+
+ treeNode.text += ": " + node;
+ treeNode.leaf = true;
+
+ return treeNode;
},
-
statics: {
- /**
- * Displays the exception window.
- *
- * The exception object may contain the following members:
- * - message: The message to display [mandatory]
- * - detail: Details about the message [optional]
- * - exception: Exception details [optional]
- * - backtrace: The backtrace [optional]
- *
- * The request data object may contain the following members:
- * - request: The request data
- * - response: The response data
- *
- * Any members specified are strings. Any other data type is not supported.
- *
- * @param exception The exception object
- * @param response The response object
- */
- showException: function (exception, response) {
- if (!PartKeepr.ExceptionWindow.activeInstance) {
- PartKeepr.ExceptionWindow.activeInstance = new PartKeepr.ExceptionWindow();
- }
-
- PartKeepr.ExceptionWindow.activeInstance._showException(exception, response);
- }
-
+ /**
+ * Displays the exception window.
+ *
+ * @param {PartKeepr.data.HydraException} exception The exception object
+ * @param {Object} response The response object
+ */
+ showException: function (exception, response)
+ {
+ if (!PartKeepr.ExceptionWindow.activeInstance) {
+ PartKeepr.ExceptionWindow.activeInstance = new PartKeepr.ExceptionWindow();
+ }
+
+ PartKeepr.ExceptionWindow.activeInstance._showException(exception, response);
+ }
+
}
});
\ No newline at end of file
diff --git a/src/PartKeepr/FrontendBundle/Resources/views/index.html.twig b/src/PartKeepr/FrontendBundle/Resources/views/index.html.twig
@@ -51,11 +51,13 @@
'@PartKeeprFrontendBundle/Resources/public/js/Ext.ux/ClearableComboBox.js'
'@PartKeeprFrontendBundle/Resources/public/js/Util/ServiceCall.js'
'@PartKeeprFrontendBundle/Resources/public/js/org.jerrymouse.util.locale/locale.js'
+ '@PartKeeprFrontendBundle/Resources/public/js/Data/HydraException.js'
'@PartKeeprFrontendBundle/Resources/public/js/Dialogs/ExceptionWindow.js'
'@PartKeeprFrontendBundle/Resources/public/js/Dialogs/FileUploadDialog.js'
'@PartKeeprFrontendBundle/Resources/public/js/Dialogs/RememberChoiceMessageBox.js'
'@PartKeeprFrontendBundle/Resources/public/js/Data/HydraProxy.js'
'@PartKeeprFrontendBundle/Resources/public/js/Data/HydraModel.js'
+ '@PartKeeprFrontendBundle/Resources/public/js/Data/HydraTreeModel.js'
'@PartKeeprFrontendBundle/Resources/public/js/Data/HydraReader.js'
'@PartKeeprFrontendBundle/Resources/public/js/Components/Statusbar.js'
'@PartKeeprFrontendBundle/Resources/public/js/Components/Auth/LoginDialog.js'