partkeepr

fork of partkeepr
git clone https://git.e1e0.net/partkeepr.git
Log | Files | Refs | Submodules | README | LICENSE

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:
Asrc/PartKeepr/FrontendBundle/Resources/public/js/Data/HydraException.js | 43+++++++++++++++++++++++++++++++++++++++++++
Msrc/PartKeepr/FrontendBundle/Resources/public/js/Dialogs/ExceptionWindow.js | 466+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Msrc/PartKeepr/FrontendBundle/Resources/views/index.html.twig | 2++
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'