brooklyn-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From henev...@apache.org
Subject [02/11] git commit: jsgui: re-support adding locations to the catalogue
Date Wed, 03 Sep 2014 16:15:29 GMT
jsgui: re-support adding locations to the catalogue


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/17f04a0a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/17f04a0a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/17f04a0a

Branch: refs/heads/master
Commit: 17f04a0ade20890c52ad50003adfa0aa1b862c76
Parents: e0e56f4
Author: Sam Corbett <sam.corbett@cloudsoftcorp.com>
Authored: Tue Aug 12 15:13:14 2014 +0100
Committer: Sam Corbett <sam.corbett@cloudsoftcorp.com>
Committed: Tue Sep 2 11:26:50 2014 +0100

----------------------------------------------------------------------
 .../webapp/assets/js/libs/brooklyn-utils.js     |  16 +++
 .../main/webapp/assets/js/libs/brooklyn-view.js |  24 +++-
 .../src/main/webapp/assets/js/model/location.js |   7 +-
 .../js/view/catalog-add-location-modal.js       | 115 -------------------
 .../src/main/webapp/assets/js/view/catalog.js   |  69 +++++++++--
 .../assets/tpl/catalog/add-catalog-entry.html   |   1 +
 .../assets/tpl/catalog/add-location-modal.html  |  66 -----------
 .../webapp/assets/tpl/catalog/add-location.html |  37 ++++++
 .../assets/tpl/catalog/details-entity.html      |  26 ++---
 .../assets/tpl/catalog/details-location.html    |   8 +-
 .../assets/tpl/catalog/location-config.html     |  24 ----
 .../webapp/assets/tpl/catalog/nav-entry.html    |   2 +-
 .../src/test/javascript/specs/brooklyn-spec.js  |   4 +-
 .../javascript/specs/brooklyn-utils-spec.js     |  18 +++
 14 files changed, 170 insertions(+), 247 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/17f04a0a/usage/jsgui/src/main/webapp/assets/js/libs/brooklyn-utils.js
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/js/libs/brooklyn-utils.js b/usage/jsgui/src/main/webapp/assets/js/libs/brooklyn-utils.js
index 1fc8905..acd8135 100644
--- a/usage/jsgui/src/main/webapp/assets/js/libs/brooklyn-utils.js
+++ b/usage/jsgui/src/main/webapp/assets/js/libs/brooklyn-utils.js
@@ -109,6 +109,22 @@ define([
         return model;
     };
 
+    /**
+     * Parses xhrResponse.responseText as JSON and returns its message. Returns
+     * alternate message if parsing fails or the parsed object has no message.
+     * @param {jqXHR} xhrResponse
+     * @param {string} alternateMessage
+     * @returns {*}
+     */
+    Util.extractError = function (xhrResponse, alternateMessage) {
+        try {
+            var response = JSON.parse(xhrResponse.responseText);
+            return response.message ? response.message : alternateMessage;
+        } catch (e) {
+            return alternateMessage;
+        }
+    };
+
     return Util;
 
 });

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/17f04a0a/usage/jsgui/src/main/webapp/assets/js/libs/brooklyn-view.js
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/js/libs/brooklyn-view.js b/usage/jsgui/src/main/webapp/assets/js/libs/brooklyn-view.js
index 5bc2bc7..3511b61 100644
--- a/usage/jsgui/src/main/webapp/assets/js/libs/brooklyn-view.js
+++ b/usage/jsgui/src/main/webapp/assets/js/libs/brooklyn-view.js
@@ -84,6 +84,8 @@ define([
     /**
      * A form that listens to modifications to its inputs, maintaining a model that is
      * submitted when a button with class 'submit' is clicked.
+     *
+     * Expects a body view or a template function to render.
      */
     module.Form = Backbone.View.extend({
         events: {
@@ -92,20 +94,30 @@ define([
         },
 
         initialize: function() {
-            if (!this.options.template) {
-                throw new Error("template required by GenericForm");
+            if (!this.options.body && !this.options.template) {
+                throw new Error("body view or template function required by GenericForm");
             } else if (!this.options.onSubmit) {
                 throw new Error("onSubmit function required by GenericForm");
             }
             this.onSubmitCallback = this.options.onSubmit;
-            this.template = _.template(this.options.template);
             this.model = new (this.options.model || Backbone.Model);
             _.bindAll(this, "onSubmit", "onChange");
             this.render();
         },
 
+        beforeClose: function() {
+            if (this.options.body) {
+                this.options.body.close();
+            }
+        },
+
         render: function() {
-            this.$el.html(this.template());
+            if (this.options.body) {
+                this.options.body.render();
+                this.$el.html(this.options.body.$el);
+            } else {
+                this.$el.html(this.options.template());
+            }
             // Initialise the model with existing values
             Util.bindModelFromForm(this.model, this.$el);
             return this;
@@ -119,8 +131,8 @@ define([
 
         onSubmit: function(e) {
             e.preventDefault();
-            // TODO: Could validate model
-            this.onSubmitCallback(this.model);
+            // Could validate model
+            this.onSubmitCallback(this.model.clone());
             return false;
         }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/17f04a0a/usage/jsgui/src/main/webapp/assets/js/model/location.js
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/js/model/location.js b/usage/jsgui/src/main/webapp/assets/js/model/location.js
index cf38bad..6d45478 100644
--- a/usage/jsgui/src/main/webapp/assets/js/model/location.js
+++ b/usage/jsgui/src/main/webapp/assets/js/model/location.js
@@ -24,13 +24,9 @@ define(["underscore", "backbone"], function (_, Backbone) {
         urlRoot:'/v1/locations',
         defaults:function () {
             return {
-                id:'',
                 name:'',
                 spec:'',
-                config:{},
-                links:{
-                    self:''
-                }
+                config:{}
             }
         },
         idFromSelfLink:function () {
@@ -79,6 +75,7 @@ define(["underscore", "backbone"], function (_, Backbone) {
 
     Location.Collection = Backbone.Collection.extend({
         model:Location.Model,
+        comparator: "name",
         url:'/v1/locations'
     })
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/17f04a0a/usage/jsgui/src/main/webapp/assets/js/view/catalog-add-location-modal.js
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/js/view/catalog-add-location-modal.js b/usage/jsgui/src/main/webapp/assets/js/view/catalog-add-location-modal.js
deleted file mode 100644
index b54ff49..0000000
--- a/usage/jsgui/src/main/webapp/assets/js/view/catalog-add-location-modal.js
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
-*/
-/**
- * Modal dialog to add a new location.
- */
-define([
-    "underscore", "jquery", "backbone", 
-    "text!tpl/catalog/add-location-modal.html", "text!tpl/catalog/location-config.html",
-    "bootstrap"
-], function (_, $, Backbone, LocationModalHtml, LocationConfigHtml) {
-
-    var LocationModalView = Backbone.View.extend({
-        tagName:'div',
-        className:'modal hide fade',
-        id:'new-location-modal',
-        events:{
-            'click #add-location-config':'addLocationConfig',
-            'click .remove':'removeLocationConfig',
-            'click #new-location-submit':'newLocationSubmit',
-            'click #show-config-form':'showConfigForm',
-            'blur #provider':'updateLocationName'
-        },
-        template:_.template(LocationModalHtml),
-        addedConfigTemplate:_.template(LocationConfigHtml),
-
-        initialize:function () {
-            _.bindAll(this, 'render')
-        },
-        render:function (eventName) {
-            this.$el.html(this.template({}))
-            this.renderLocationName()
-            this.renderAddedConfigs()
-            return this
-        },
-        renderLocationName:function () {
-            this.$('#provider').val(this.model.get("provider"))
-        },
-        renderAddedConfigs:function () {
-            var $addedConfigs = this.$('#added-configs ul').empty(),
-                that = this
-            _.each(this.model.get("config"), function (theValue, theKey) {
-                $addedConfigs.append(that.addedConfigTemplate({ key:theKey, value:theValue}))
-            })
-        },
-        removeLocationConfig:function (event) {
-            var key = $(event.currentTarget).parent().find('span.key').html()
-            this.model.removeConfig(key)
-            this.render()
-        },
-        newLocationSubmit:function (event) {
-            event.preventDefault()
-            if (this.isNewLocationValid()) {
-                var self = this
-                Backbone.sync('create', this.model, {
-                    success:function () {
-                        self.options.appRouter.navigate("v1/locations")
-                    }
-
-                })
-                this.$el.modal('hide')
-                this.$el.empty()
-            } else {
-                this.showMessage('A location must have a non-empty name and at least one
configuration.')
-            }
-        },
-        updateLocationName:function (eventName) {
-            this.model.set("provider", this.$('#provider').val())
-            this.render()
-        },
-        isNewLocationValid:function () {
-            if (this.model.get("provider").length == 0 || _.isEmpty(this.model.get("config")))
{
-                return false
-            }
-            return true
-        },
-        addLocationConfig:function (event) {
-            // add a new key-value option to the new location form
-            var key = $.trim(this.$('input#key').val())
-            if (key.length != 0) {
-                this.model.addConfig(key, this.$('input#value').val())
-                this.render()
-            } else {
-                this.showMessage('Key must not be empty!')
-            }
-            return false
-        },
-        showConfigForm:function () {
-            this.$('#config-form').show()
-        },
-        showMessage:function (message) {
-            var $div = this.$('div.info-message')
-            $div.find('span#message').html(message)
-            $div.show('slow').delay(2000).hide('slow')
-            return false
-        }
-    })
-
-    return LocationModalView
-})
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/17f04a0a/usage/jsgui/src/main/webapp/assets/js/view/catalog.js
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/js/view/catalog.js b/usage/jsgui/src/main/webapp/assets/js/view/catalog.js
index 06ba9ac..24389d9 100644
--- a/usage/jsgui/src/main/webapp/assets/js/view/catalog.js
+++ b/usage/jsgui/src/main/webapp/assets/js/view/catalog.js
@@ -25,13 +25,14 @@ define([
     "text!tpl/catalog/details-location.html",
     "text!tpl/catalog/add-catalog-entry.html",
     "text!tpl/catalog/add-entity.html",
+    "text!tpl/catalog/add-location.html",
     "text!tpl/catalog/nav-entry.html",
 
     "bootstrap", "jquery-form"
 ], function(_, $, Backbone, FormatJSON, Brooklyn,
         Location, Entity,
         CatalogPageHtml, DetailsEntityHtml, DetailsGenericHtml, LocationDetailsHtml,
-        AddCatalogEntryHtml, AddEntityHtml, EntryHtml) {
+        AddCatalogEntryHtml, AddEntityHtml, AddLocationHtml, EntryHtml) {
 
     // Holds the currently active details type, e.g. applications, policies. Bit of a workaround
     // to share the active view with all instances of AccordionItemView, so clicking the
'reload
@@ -39,7 +40,6 @@ define([
     // more than one element.
     var activeDetailsView;
 
-    // TODO: Loading item's details should perform page navigation
     var CatalogItemDetailsView = Backbone.View.extend({
 
         events: {
@@ -154,6 +154,8 @@ define([
             this.context = type;
             if (type == "entity") {
                 this.contextView = newEntityForm(this.options.parent);
+            } else if (type == "location") {
+                this.contextView = newLocationForm(this.options.parent);
             } else if (type !== undefined) {
                 console.log("unknown catalog type " + type);
                 this.showFormForType("entity");
@@ -166,7 +168,7 @@ define([
 
     function newEntityForm(parent) {
         return new Brooklyn.view.Form({
-            template: AddEntityHtml,
+            template: _.template(AddEntityHtml),
             onSubmit: function (model) {
                 console.log("Submit entity", model.get("yaml"));
                 var submitButton = this.$(".catalog-submit-button");
@@ -186,20 +188,59 @@ define([
                         parent.loadAccordionItem("entities", data.id);
                     })
                     .fail(function (xhr, status, error) {
-                        var message;
-                        try {
-                            message = JSON.parse(xhr.responseText).message;
-                        } catch (e) {
-                            message = "Error adding catalog item: " + error;
-                        }
                         submitButton.button("reset");
                         self.$(".catalog-save-error")
                             .removeClass("hide")
                             .find(".catalog-error-message")
-                            .html(message);
+                            .html(Brooklyn.util.extractError(xhr, "Error adding catalog item:
" + error));
+                    });
+            }
+        });
+    }
+
+    // Could adapt to edit existing locations too.
+    function newLocationForm(parent) {
+        // Renders with config key list
+        var body = new (Backbone.View.extend({
+            beforeClose: function() {
+                if (this.configKeyList) {
+                    this.configKeyList.close();
+                }
+            },
+            render: function() {
+                this.configKeyList = new Brooklyn.view.ConfigKeyInputPairList().render();
+                var template = _.template(AddLocationHtml);
+                this.$el.html(template);
+                this.$("#new-location-config").html(this.configKeyList.$el);
+            },
+            showError: function (message) {
+                self.$(".catalog-save-error")
+                    .removeClass("hide")
+                    .find(".catalog-error-message")
+                    .html(message);
+            }
+        }));
+        var form = new Brooklyn.view.Form({
+            body: body,
+            model: Location.Model,
+            onSubmit: function (location) {
+                var configKeys = body.configKeyList.getConfigKeys();
+                if (!configKeys.displayName) {
+                    configKeys.displayName = location.get("name");
+                }
+                location.set("config", configKeys);
+                location.save()
+                    .done(function (newModel) {
+                        newModel = new Location.Model(newModel);
+                        parent.loadAccordionItem("locations", newModel.id);
+                    })
+                    .fail(function (response) {
+                        body.showError(Brooklyn.util.extractError(response));
                     });
             }
         });
+
+        return form;
     }
 
     var Catalog = Backbone.Collection.extend({
@@ -342,12 +383,14 @@ define([
             this.accordion = this.options.accordion || {
                 "applications": new AccordionItemView({
                     name: "applications",
+                    singular: "application",
                     onItemSelected: _.partial(this.showCatalogItem, DetailsEntityHtml),
                     model: Entity.Model,
                     autoOpen: !this.options.kind || this.options.kind == "applications"
                 }),
                 "entities": new AccordionItemView({
                     name: "entities",
+                    singular: "entity",
                     onItemSelected: _.partial(this.showCatalogItem, DetailsEntityHtml),
                     model: Entity.Model,
                     autoOpen: this.options.kind == "entities"
@@ -355,10 +398,12 @@ define([
                 "policies": new AccordionItemView({
                     onItemSelected: _.partial(this.showCatalogItem, DetailsEntityHtml),
                     name: "policies",
+                    singular: "policy",
                     autoOpen: this.options.kind == "policies"
                 }),
                 "locations": new AccordionItemView({
                     name: "locations",
+                    singular: "location",
                     onItemSelected: _.partial(this.showCatalogItem, LocationDetailsHtml),
                     collection: this.options.locations,
                     autoOpen: this.options.kind == "locations",
@@ -420,11 +465,13 @@ define([
                 console.error("No accordion for: " + kind);
             } else {
                 var accordion = this.accordion[kind];
+                var self = this;
                 accordion.collection.fetch()
                     .then(function() {
                         var model = accordion.collection.get(id);
                         if (!model) {
-                            console.log("Accordion for " + kind + " has no element with id
" + id);
+                            self.setDetailsView(new CatalogItemDetailsView().renderEmpty(
+                                    "No " + accordion.options.singular + " with id: " + id));
                         } else {
                             activeDetailsView = kind;
                             accordion.activeCid = model.cid;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/17f04a0a/usage/jsgui/src/main/webapp/assets/tpl/catalog/add-catalog-entry.html
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/tpl/catalog/add-catalog-entry.html b/usage/jsgui/src/main/webapp/assets/tpl/catalog/add-catalog-entry.html
index 16fb9ee..6bd8c00 100644
--- a/usage/jsgui/src/main/webapp/assets/tpl/catalog/add-catalog-entry.html
+++ b/usage/jsgui/src/main/webapp/assets/tpl/catalog/add-catalog-entry.html
@@ -23,6 +23,7 @@ under the License.
 
     <div data-toggle="buttons-radio">
         <button class="btn btn-large show-context" data-context="entity">Entity</button>
+        <button class="btn btn-large show-context" data-context="location">Location</button>
     </div>
 
     <hr/>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/17f04a0a/usage/jsgui/src/main/webapp/assets/tpl/catalog/add-location-modal.html
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/tpl/catalog/add-location-modal.html b/usage/jsgui/src/main/webapp/assets/tpl/catalog/add-location-modal.html
deleted file mode 100644
index cadd6fc..0000000
--- a/usage/jsgui/src/main/webapp/assets/tpl/catalog/add-location-modal.html
+++ /dev/null
@@ -1,66 +0,0 @@
-<!--
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
--->
-
-<!-- Modal window for adding a new location to the catalog -->
-<div class="modal-header">
-    <button type="button" class="close" data-dismiss="modal">x</button>
-    <h3>Add a new Location</h3>
-</div>
-<div class="modal-body">
-    <div class="row">
-        <div class="span5">
-
-            <label for="provider" class="control-label">Provider name:</label>
-
-            <div class="control-group">
-                <div class="controls">
-                    <input id="provider" name="provider" type="text" placeholder="Provider"
-                           class="input-large">
-                </div>
-            </div>
-
-            <div id="added-configs">
-                <h4>Location configuration</h4>
-                <ul/>
-            </div>
-            <dl class="dl-horizontal"></dl>
-            <button id="show-config-form" class="btn btn-info btn-mini">Add configuration
key-value</button>
-            <dl class="dl-horizontal"></dl>
-            <div id="config-form" class="hide">
-                <input id="key" type="text" class="input-medium" placeholder="key">
-                <input id="value" type="text" class="input-medium" placeholder="value">
-                <button id="add-location-config" class="btn btn-inverted btn-mini" type="button">
-                    <i class="icon-br-plus-sign"></i>
-                </button>
-            </div>
-        </div>
-    </div>
-    <dl class="dl-horizontal"></dl>
-    <div class="info-message hide">
-        <p>
-            <span class="label-important">Important</span>
-            <span id="message">A location must have at least one config.</span>
-        </p>
-    </div>
-</div>
-
-<div class="modal-footer">
-    <button class="btn" data-dismiss="modal" type="button">Close</button>
-    <button id="new-location-submit" class="btn btn-primary" type="button">Save</button>
-</div>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/17f04a0a/usage/jsgui/src/main/webapp/assets/tpl/catalog/add-location.html
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/tpl/catalog/add-location.html b/usage/jsgui/src/main/webapp/assets/tpl/catalog/add-location.html
new file mode 100644
index 0000000..e57b83a
--- /dev/null
+++ b/usage/jsgui/src/main/webapp/assets/tpl/catalog/add-location.html
@@ -0,0 +1,37 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<form>
+    <label for="name" class="control-label">Name</label>
+    <input id="name" name="name" type="text" placeholder="e.g. My Cloud Region #3" class="input-xlarge">
+
+    <label for="spec" class="control-label">Spec</label>
+    <input id="spec" name="spec" type="text" placeholder="e.g. jclouds:cloud:region" class="input-xlarge">
+
+    <h4>Configuration</h4>
+    <div id="new-location-config"></div>
+
+    <button class='catalog-submit-button btn' data-loading-text='Saving...'>Submit</button>
+
+    <p class="catalog-save-error hide">
+        <span class="alert-error">
+            <strong>Error:</strong><br/>
+            <span class="catalog-error-message"></span>
+        </span>
+    </p>
+</form>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/17f04a0a/usage/jsgui/src/main/webapp/assets/tpl/catalog/details-entity.html
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/tpl/catalog/details-entity.html b/usage/jsgui/src/main/webapp/assets/tpl/catalog/details-entity.html
index fda1da1..60768d5 100644
--- a/usage/jsgui/src/main/webapp/assets/tpl/catalog/details-entity.html
+++ b/usage/jsgui/src/main/webapp/assets/tpl/catalog/details-entity.html
@@ -18,9 +18,9 @@ under the License.
 -->
 <div class="catalog-details">
 
-    <h2><%= model.get("name") %></h2>
-    <p><%= model.get("id") %></p>
-    <p><%= model.get("description") %></p>
+    <h2><%- model.get("name") %></h2>
+    <p><%- model.get("id") %></p>
+    <p><%- model.get("description") %></p>
 
     <div id="catalog-details-accordion" class="accordion">
         <div class="accordion-group">
@@ -32,7 +32,7 @@ under the License.
             <div id="collapseYaml" class="accordion-body collapse">
                 <div class="accordion-inner">
                     <% if (model.get("planYaml")) { %>
-                    <textarea rows="15" readonly><%= model.get("planYaml") %></textarea>
+                    <textarea rows="15" readonly><%- model.get("planYaml") %></textarea>
                     <% } else { %>
                     <p>No plan</p>
                     <% } %>
@@ -63,14 +63,14 @@ under the License.
                             'reconfigurable'
                         ]; %>
                         <% _.each(model.get("config"), function(object, index) { %>
-                        <p><strong><%= object.name %></strong>: <%=
object.description %></p>
+                        <p><strong><%- object.name %></strong>: <%-
object.description %></p>
                         <table class="table table-striped table-condensed nonDatatables">
                             <tbody>
                             <% _.each(object, function(value, key) { %>
                             <% if (!_.contains(skip, key)) { %>
                             <tr>
-                                <td><%= key %></td>
-                                <td><%= value %></td>
+                                <td><%- key %></td>
+                                <td><%- value %></td>
                             </tr>
                             <% } %>
                             <% }); %>
@@ -107,9 +107,9 @@ under the License.
                             <tbody>
                             <% _.each(model.get("sensors"), function(object, index) {
%>
                                 <tr>
-                                    <td><%= object.name %></td>
-                                    <td><%= object.type %></td>
-                                    <td><%= object.description %></td>
+                                    <td><%- object.name %></td>
+                                    <td><%- object.type %></td>
+                                    <td><%- object.description %></td>
                                 </tr>
                             <% }); %>
                             </tbody>
@@ -134,7 +134,7 @@ under the License.
                     <p>No effectors</p>
                 <% } else { %>
                     <% _.each(model.get("effectors"), function(object, index) { %>
-                        <p><strong><%= object.name %></strong>: <%=
object.description %></p>
+                        <p><strong><%- object.name %></strong>: <%-
object.description %></p>
                         <% if (!object.parameters || _.isEmpty(object.parameters)) { %>
                             <p>No parameters</p>
                         <% } else { %>
@@ -143,8 +143,8 @@ under the License.
                                     <% _.each(object.parameters, function(parameter, index)
{ %>
                                         <% _.each(parameter, function(value, key) { %>
                                         <tr>
-                                            <td><%= key %></td>
-                                            <td><%= value %></td>
+                                            <td><%- key %></td>
+                                            <td><%- value %></td>
                                         </tr>
                                         <% }); %>
                                     <% }); %>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/17f04a0a/usage/jsgui/src/main/webapp/assets/tpl/catalog/details-location.html
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/tpl/catalog/details-location.html b/usage/jsgui/src/main/webapp/assets/tpl/catalog/details-location.html
index 4d93207..27fe3e2 100644
--- a/usage/jsgui/src/main/webapp/assets/tpl/catalog/details-location.html
+++ b/usage/jsgui/src/main/webapp/assets/tpl/catalog/details-location.html
@@ -18,7 +18,7 @@ under the License.
 -->
 <div class="catalog-details">
 
-    <h3><%= model.getPrettyName() %></h3>
+    <h3><%- model.getPrettyName() %></h3>
 
     <div class="float-right">
         <button data-name="<%= model.getPrettyName() %>" class="btn btn-danger delete">Delete</button>
@@ -30,9 +30,9 @@ under the License.
 
     <br/>
     <table>
-        <tr><td><strong>ID:</strong>&nbsp;&nbsp;</td><td><%=
model.get("id") || "" %></td></tr>
-        <tr><td><strong>Name:</strong>&nbsp;&nbsp;</td><td><%=
model.get("name") || "" %></td></tr>
-        <tr><td><strong>Spec:</strong>&nbsp;&nbsp;</td><td><%=
model.get("spec") || "" %></td></tr>
+        <tr><td><strong>ID:</strong>&nbsp;&nbsp;</td><td><%-
model.get("id") || "" %></td></tr>
+        <tr><td><strong>Name:</strong>&nbsp;&nbsp;</td><td><%-
model.get("name") || "" %></td></tr>
+        <tr><td><strong>Spec:</strong>&nbsp;&nbsp;</td><td><%-
model.get("spec") || "" %></td></tr>
     </table>
     
     <br/>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/17f04a0a/usage/jsgui/src/main/webapp/assets/tpl/catalog/location-config.html
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/tpl/catalog/location-config.html b/usage/jsgui/src/main/webapp/assets/tpl/catalog/location-config.html
deleted file mode 100644
index 91c980f..0000000
--- a/usage/jsgui/src/main/webapp/assets/tpl/catalog/location-config.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
--->
-
-<!-- Template for rendering a key-value configuration inside the new location form -->
-<li>
-    <span class="key"><%= key %></span> : <span class="value"><%=
value %></span>
-    <span class="icon-remove-sign remove" style="margin-left:10px;"></span>
-</li>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/17f04a0a/usage/jsgui/src/main/webapp/assets/tpl/catalog/nav-entry.html
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/tpl/catalog/nav-entry.html b/usage/jsgui/src/main/webapp/assets/tpl/catalog/nav-entry.html
index 9c6dcbf..36a8588 100644
--- a/usage/jsgui/src/main/webapp/assets/tpl/catalog/nav-entry.html
+++ b/usage/jsgui/src/main/webapp/assets/tpl/catalog/nav-entry.html
@@ -16,4 +16,4 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 -->
-<div data-cid="<%= cid %>" class="accordion-nav-row <%= extraClasses %>"><%=
type %></div>
+<div data-cid="<%= cid %>" class="accordion-nav-row <%= extraClasses %>"><%-
type %></div>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/17f04a0a/usage/jsgui/src/test/javascript/specs/brooklyn-spec.js
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/test/javascript/specs/brooklyn-spec.js b/usage/jsgui/src/test/javascript/specs/brooklyn-spec.js
index 8c9642d..3f301a4 100644
--- a/usage/jsgui/src/test/javascript/specs/brooklyn-spec.js
+++ b/usage/jsgui/src/test/javascript/specs/brooklyn-spec.js
@@ -22,11 +22,11 @@ define([
 
     describe("view", function () {
         describe("form", function() {
-            var formTemplate = '<form>' +
+            var formTemplate = _.template('<form>' +
                 '<input name="id" type="text"/>' +
                 '<input name="initialvalue" type="text" value="present"/>' +
                 '<button type="submit" class="submit">Submit</button>' +
-                '</form>';
+                '</form>');
 
             it("should set existing values on the model", function() {
                 var form = new B.view.Form({template: formTemplate, onSubmit: function()
{}});

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/17f04a0a/usage/jsgui/src/test/javascript/specs/brooklyn-utils-spec.js
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/test/javascript/specs/brooklyn-utils-spec.js b/usage/jsgui/src/test/javascript/specs/brooklyn-utils-spec.js
index ab9566d..4c21f50 100644
--- a/usage/jsgui/src/test/javascript/specs/brooklyn-utils-spec.js
+++ b/usage/jsgui/src/test/javascript/specs/brooklyn-utils-spec.js
@@ -130,4 +130,22 @@ define([
             expect(inputs.initialAttribute).toBe("xyz");
         });
     });
+
+    describe("extractError", function () {
+        it("should extract the response message", function () {
+            var m = Util.extractError({ responseText: '{"message": "hello"}'}, "default");
+            expect(m).toBe("hello");
+        });
+
+        it("should return the default on invalid JSON", function () {
+            var m = Util.extractError({ responseText: "<html></html>"}, "default");
+            expect(m).toBe("default");
+        });
+
+        it("should return the default if the response has no message", function () {
+            var m = Util.extractError({ a: '{"b": "c"}'}, "default");
+            expect(m).toBe("default");
+        });
+    });
+
 });


Mime
View raw message