improvements to add-app wizard esp use of catalog - shows templates 
graphically, searchable; locations in order, and misc tidies


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

Branch: refs/heads/0.5.0
Commit: c299b33501e0431283722d3aeefbfe485629f038
Parents: 7e6c524
Author: Alex Heneveld <[email protected]>
Authored: Tue Nov 27 11:08:08 2012 -0800
Committer: Alex Heneveld <[email protected]>
Committed: Wed Nov 28 02:39:09 2012 -0800

----------------------------------------------------------------------
 .../src/main/webapp/assets/css/prettybrook.css  | 155 ++++++++++++++--
 .../main/webapp/assets/js/model/application.js  |  27 +--
 .../assets/js/model/catalog-item-summary.js     |  25 +++
 .../assets/js/view/application-add-wizard.js    | 176 +++++++++++++++----
 .../webapp/assets/js/view/application-tree.js   |   2 -
 .../src/main/webapp/assets/js/view/catalog.js   |   5 +-
 .../src/main/webapp/assets/js/view/home.js      |  20 ++-
 .../tpl/app-add-wizard/create-config-entry.html |   8 -
 .../tpl/app-add-wizard/create-entity-entry.html |   2 +-
 .../create-step-template-entry.html             |  13 ++
 .../assets/tpl/app-add-wizard/create.html       |  41 +++--
 .../assets/tpl/app-add-wizard/deploy.html       |  49 +++---
 .../tpl/app-add-wizard/edit-config-entry.html   |   8 +
 .../assets/tpl/app-add-wizard/preview.html      |  21 ++-
 .../BrooklynJavascriptGuiLauncherTest.java      |   2 +-
 .../javascript/specs/model/application-spec.js  |   4 +-
 16 files changed, 418 insertions(+), 140 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/c299b335/usage/jsgui/src/main/webapp/assets/css/prettybrook.css
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/css/prettybrook.css 
b/usage/jsgui/src/main/webapp/assets/css/prettybrook.css
index d9aae39..a699234 100644
--- a/usage/jsgui/src/main/webapp/assets/css/prettybrook.css
+++ b/usage/jsgui/src/main/webapp/assets/css/prettybrook.css
@@ -18,7 +18,67 @@
        margin-top: 40px;
        margin-bottom: 40px;
 }
-
+#application-content .modal-body {
+    padding: 0;
+}
+#application-content ul.nav-tabs {
+    margin: 15px 15px 0px 15px;
+}
+#application-content .deploy,
+#application-content .preview {
+       padding: 15px;
+}
+#application-content .tab-content {
+    max-height: 500px;
+    overflow: scroll;
+}
+#application-content .template-lozenge {
+    cursor: hand; cursor: pointer;
+}
+#application-content div.template-lozenge.frame {
+    display: inline-block;
+    border: 3px solid #EEE;
+    border-radius: 4px;
+    width: 212px;
+    overflow: scroll;
+    margin: 4px;
+    padding: 3px;
+}
+#application-content div.template-lozenge div.icon {
+       margin: 2px 8px 2px 2px;
+}
+#application-content div.template-lozenge div.icon img {
+       max-width: 50px;
+       max-height: 50px;
+       margin-top: 15px;
+}
+#application-content .template-lozenge.frame:hover {
+    border: 3px solid #CCC;
+}
+#application-content .template-lozenge.frame.selected {
+    border: 3px solid #793;
+}
+#application-content .template-lozenge .icon {
+       float: left;
+}
+#application-content .template-lozenge .blurb {
+    overflow-y: scroll;
+    height: 80px;
+}
+#application-content .template-lozenge .title {
+    font-weight: 700;
+    font-size: 90%;
+}
+#application-content .template-lozenge .description {
+       font-size: 85%;
+}
+div#create-step-template-entries {
+       width: 472px;
+       margin-left: auto;
+       margin-right: auto;
+       padding-top: 12px;
+       padding-bottom: 36px;
+}
 /* menu bar */
 .navbar .nav>li {
        display: block;
@@ -79,6 +139,22 @@ ul.dropdown-menu {
        border-radius: 5px 5px 0 0;
 }
 
+li.text-filter input {
+       width: 10em;
+       margin-top: 3px;
+    /* taken from datatables_filter input */   
+    background-image: url("../img/magnifying-glass-right.png");
+    background-size:12px 12px;
+    background-repeat: no-repeat;
+    background-position: 8px 5px;
+    font-size: 85%;
+    padding: 1px 4px 1px 24px;
+    margin-bottom: 2px;
+    -webkit-border-radius: 1em;
+    -moz-border-radius: 1em;
+    border-radius: 1em;
+}
+
 /* bootstrap overrides */
 a {
     color: #382;
@@ -152,6 +228,21 @@ code {
 }
 */
 
+textarea:focus,input[type="text"]:focus,input[type="password"]:focus,
+input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,
+input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,
+input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,
+input[type="color"]:focus,.uneditable-input:focus {
+       border-color: rgba(120, 180, 70, 0.8);
+       outline: 0;
+       outline: thin dotted 9;
+       -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px
+               rgba(120, 180, 70, 0.6);
+       -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px
+               rgba(120, 180, 70, 0.6);
+       box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px
+               rgba(120, 180, 70, 0.6);
+}
 
 /* home page squares */
 
@@ -312,11 +403,15 @@ code {
 .nav-tabs {
        margin-bottom: 0px;
 }
+.tab-content-scroller {
+    overflow: scroll;
+    height: auto;
+}
 .tab-content {
-       padding: 18px 12px 18px 12px;
+       padding: 18px 24px 18px 24px;
     border-right: 1px solid #DDD;
     border-left: 1px solid #DDD;
-    min-height: 500px;
+    min-height: 300px;
 }
 #tree-list {
 }
@@ -560,9 +655,17 @@ div.for-empty-table {
     -moz-border-radius: 4px;
     border-radius: 4px;
 }
-.app-add-wizard-create-entity-config input {
+
+.app-add-wizard-config-entry input {
     margin-bottom: 0px;        
 }
+.app-add-wizard-config-entry {
+       margin-bottom: 9px;
+       margin-top: 2px;
+}
+.app-add-wizard-config-entry button {
+       margin-left: 8px;
+}
 .app-add-wizard-create-entity-label-newline {
     padding-left: 2px;
     padding-bottom: 3px;       
@@ -575,13 +678,6 @@ div.for-empty-table {
 .app-add-wizard-create-entity-input {
        width: 300px;
 }
-.app-add-wizard-create-entity-config {
-       margin-bottom: 9px;
-       margin-top: 2px;
-}
-.app-add-wizard-create-entity-config button {
-       margin-left: 8px;
-}
 #add-app-entity {
        float: right;
 }
@@ -602,7 +698,16 @@ div.for-empty-table {
        margin-top: 6px;
        margin-bottom: 9px;
 }
-
+.control-group .deploy-label {
+       font-weight: 700;
+}
+.deploy .control-group {
+       margin-bottom: 18px;
+}
+.deploy input#application-name {
+       /** margin supplied by control group */
+       margin-bottom: 0px;
+}
 
 #application-explorer div#summary {
     padding-right: 16px;
@@ -629,7 +734,7 @@ div.for-empty-table {
 .accordion-body {
        border-top: 1px dashed lightgray;
     padding: 8px 8px 12px 8px;
-    max-height: 350px;'
+    max-height: 400px;'
     overflow-x: scroll;
     overflow-y: scroll;
     background-color: white;
@@ -869,14 +974,14 @@ textarea {
     {
     -webkit-border-top-right-radius: 0 0 0 13px !important;
     -moz-border-top-right-radius: 0 0 0 13px !important;
-    border-bottom-right-radius: 13px;
+    border-bottom-left-radius: 13px;
 }
 
 .table-bordered thead:last-child tr:last-child th:last-child,.table-bordered 
tbody:last-child tr:last-child td:last-child
     {
     -webkit-border-top-right-radius: 0 0 13px 0 !important;
     -moz-border-top-right-radius: 0 0 13px 0 !important;
-    border-bottom-left-radius: 13px;
+    border-bottom-right-radius: 13px;
 }
 /*HOME BODY */
 
@@ -968,13 +1073,20 @@ textarea {
 }
 
 .nav-tabs>.active>a,.nav-tabs>.active {
-    color: #549e2b !important;
+    color: #549e2b;
 }
 
 .nav-tabs>.active>a,.nav-tabs>.active a {
     background: #ffffff !important;
 }
 
+.nav-tabs .dropdown-menu li > a:hover, 
+.nav-tabs .dropdown-menu .active > a,
+.nav-tabs .dropdown-menu .active > a:hover {
+    color: white;
+    background-color: #549e2b !important;
+}
+
 .nav-tabs>li>a {
     color: #444444 !important;
     border: 1px solid #dddddd !important;
@@ -988,6 +1100,17 @@ textarea {
     color: #549e2b !important;
     background: #ffffff none !important;
 }
+.nav-tabs .dropdown-toggle .caret, .nav-pills .dropdown-toggle .caret {
+    opacity: 0.5;
+       margin-top: 6px;
+    border-top-color: #000;
+    border-bottom-color: #000;
+}
+.nav-tabs .dropdown-toggle:hover .caret, .nav-pills .dropdown-toggle:hover 
.caret {
+       opacity: 0.8;
+    border-top-color: #549e2b;
+    border-bottom-color: #549e2b;
+}
 
 #effectors-table th {
     background: #ffffff !important

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/c299b335/usage/jsgui/src/main/webapp/assets/js/model/application.js
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/js/model/application.js 
b/usage/jsgui/src/main/webapp/assets/js/model/application.js
index 4a7597a..3ec4fae 100644
--- a/usage/jsgui/src/main/webapp/assets/js/model/application.js
+++ b/usage/jsgui/src/main/webapp/assets/js/model/application.js
@@ -12,7 +12,7 @@ define([
             return {
                 name:"",
                 type:null,
-                entities:[],
+                entities:null,
                 locations:[]
             }
         },
@@ -55,18 +55,25 @@ define([
             }
             this.set('locations', newLocations)
         },
-        addEntity:function (entity) {
+        getEntities: function() {
             var entities = this.get('entities')
-            if (!this.hasEntityWithName(entity.get("name"))) {
-                entities.push(entity.toJSON())
-                this.set('entities', entities)
-                this.trigger("change")
-                this.trigger("change:entities")
+            if (entities === undefined) return [];
+            return entities;
+        },
+        addEntity:function (entity) {
+            var entities = this.getEntities()
+            if (!entities) {
+                entities = []
+                this.set("entities", entities)
             }
+            entities.push(entity.toJSON())
+            this.set('entities', entities)
+            this.trigger("change")
+            this.trigger("change:entities")
         },
         removeEntityIndex:function (indexToRemove) {
             var newEntities = [],
-                currentEntities = this.get("entities")
+                currentEntities = this.getEntities()
             for (var index=0; index<currentEntities.length; index++) {
                 if (index != indexToRemove)
                     newEntities.push(currentEntities[index])
@@ -75,7 +82,7 @@ define([
         },
         removeEntityByName:function (name) {
             var newEntities = [],
-                currentEntities = this.get("entities")
+                currentEntities = this.getEntities()
             for (var index in currentEntities) {
                 if (currentEntities[index].name != name)
                     newEntities.push(currentEntities[index])
@@ -83,7 +90,7 @@ define([
             this.set('entities', newEntities)
         },
         hasEntityWithName:function (name) {
-            return _.any(this.get('entities'), function (entity) {
+            return _.any(this.getEntities(), function (entity) {
                 return entity.name === name
             })
         }

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/c299b335/usage/jsgui/src/main/webapp/assets/js/model/catalog-item-summary.js
----------------------------------------------------------------------
diff --git 
a/usage/jsgui/src/main/webapp/assets/js/model/catalog-item-summary.js 
b/usage/jsgui/src/main/webapp/assets/js/model/catalog-item-summary.js
new file mode 100644
index 0000000..559a16e
--- /dev/null
+++ b/usage/jsgui/src/main/webapp/assets/js/model/catalog-item-summary.js
@@ -0,0 +1,25 @@
+define(["underscore", "backbone"], function (_, Backbone) {
+
+    // not used currently
+    
+    var CatalogItem = {}
+
+    CatalogItem.Model = Backbone.Model.extend({
+        defaults:function () {
+            return {
+                id:"",
+                name:"",
+                type:"",
+                description:"",
+                iconUrl:"",
+            }
+        },
+    })
+
+    CatalogItem.Collection = Backbone.Collection.extend({
+        model:CatalogItem.Model,
+        url:'/v1/catalog'  // not used?
+    })
+
+    return CatalogItem
+})
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/c299b335/usage/jsgui/src/main/webapp/assets/js/view/application-add-wizard.js
----------------------------------------------------------------------
diff --git 
a/usage/jsgui/src/main/webapp/assets/js/view/application-add-wizard.js 
b/usage/jsgui/src/main/webapp/assets/js/view/application-add-wizard.js
index f68ef29..1a7f141 100644
--- a/usage/jsgui/src/main/webapp/assets/js/view/application-add-wizard.js
+++ b/usage/jsgui/src/main/webapp/assets/js/view/application-add-wizard.js
@@ -6,8 +6,10 @@ define([
     "underscore", "jquery", "backbone", "model/entity", "model/application", 
"formatJson",
     "model/location", "text!tpl/app-add-wizard/modal-wizard.html",
     
-    "text!tpl/app-add-wizard/create.html", 
-    "text!tpl/app-add-wizard/create-entity-entry.html", 
"text!tpl/app-add-wizard/create-config-entry.html",
+    "text!tpl/app-add-wizard/create.html",
+    "text!tpl/app-add-wizard/create-step-template-entry.html", 
+    "text!tpl/app-add-wizard/create-entity-entry.html", 
+    "text!tpl/app-add-wizard/edit-config-entry.html",
     
     "text!tpl/app-add-wizard/deploy.html", 
     "text!tpl/app-add-wizard/deploy-location-row.html", 
"text!tpl/app-add-wizard/deploy-location-option.html",
@@ -18,7 +20,7 @@ define([
     
 ], function (_, $, Backbone, Entity, Application, FormatJSON, Location, 
ModalHtml, 
                CreateHtml, 
-               CreateEntityEntryHtml, CreateConfigEntryHtml,
+               CreateStepTemplateEntryHtml, CreateEntityEntryHtml, 
EditConfigEntryHtml,
                DeployHtml, 
                DeployLocationRowHtml, DeployLocationOptionHtml,  
                PreviewHtml
@@ -39,19 +41,19 @@ define([
                           {
                               step_id:'what-app',
                               title:'Create Application',
-                              instructions:'Define how the application is 
built and the configuration parameters',
+                              instructions:'Choose or build the application to 
deploy',
                               view:new ModalWizard.StepCreate({ 
model:this.model})
                           },
                           {
                               step_id:'name-and-locations',
                               title:'Deploy Application',
-                              instructions:'Enter the name of the new 
application and the location(s) where you wish to deploy it.',
+                              instructions:'Specify the locations to deploy to 
and any additional configuration',
                               view:new ModalWizard.StepDeploy({ 
model:this.model })
                           },
                           {
                               step_id:'preview',
                               title:'Application Preview',
-                              instructions:'Confirm the code which will be 
sent to the server, optionally tweaking it or saving it for future reference.',
+                              instructions:'Confirm the code which will be 
sent to the server, optionally tweaking it or saving it for future reference',
                               view:new ModalWizard.StepPreview({ 
model:this.model})
                           }
                           ]
@@ -138,29 +140,37 @@ define([
     ModalWizard.StepCreate = Backbone.View.extend({
         className:'modal-body',
         events:{
-            'click #add-app-entity':'addEntity',
+            'click #add-app-entity':'addEntityBox',
             'click .editable-entity-heading':'expandEntity',
             'click .remove-entity-button':'removeEntityClick',
             'click .editable-entity-button':'saveEntityClick',
             'click #remove-config':'removeConfigRow',
-            'click #add-config':'addConfigRow'
+            'click #add-config':'addConfigRow',
+            'click .template-lozenge':'templateClick',
+            'change .text-filter input':'applyFilter',
+            'keyup .text-filter input':'applyFilter',
+            'shown a[data-toggle="tab"]':'onTabChange'
         },
         template:_.template(CreateHtml),
         initialize:function () {
             var self = this
-            self.catalogEntities = []
-            self.catalogApplications = []
+            self.catalogEntityIds = []
+            self.catalogApplicationIds = []
             
             this.$el.html(this.template({}))
-            this.addEntity()
+            
+            this.addEntityBox()
             
             $.get('/v1/catalog/entities', {}, function (result) {
-                self.catalogEntities = result
-                
self.$(".entity-type-input").typeahead().data('typeahead').source = 
self.catalogEntities
+                self.catalogEntityItems = result
+                self.catalogEntityIds = _.map(result, function(item) { return 
item.id })
+                
self.$(".entity-type-input").typeahead().data('typeahead').source = 
self.catalogEntityIds
             })
             $.get('/v1/catalog/applications', {}, function (result) {
-                self.catalogApplications = result
-                
self.$(".application-type-input").typeahead().data('typeahead').source = 
self.catalogApplications
+                self.catalogApplicationItems = result
+                self.catalogApplicationIds = _.map(result, function(item) { 
return item.id })
+                self.$("#appClassTab 
.application-type-input").typeahead().data('typeahead').source = 
self.catalogApplicationIds
+                self.addTemplateLozenges()
             })
         },
         beforeClose:function () {
@@ -168,7 +178,7 @@ define([
         renderConfiguredEntities:function () {
             var $configuredEntities = this.$('#entitiesAccordionish').empty()
             var that = this
-            if (this.model.get("entities").length > 0) {
+            if (this.model.get("entities") && 
this.model.get("entities").length > 0) {
                 _.each(this.model.get("entities"), function (entity) {
                     that.addEntityHtml($configuredEntities, entity)
                 })
@@ -180,18 +190,65 @@ define([
             this.delegateEvents()
             return this
         },
-        
+        onTabChange: function(e) {
+            if (e.target.text=="Template")
+                $("li.text-filter").show()
+            else
+                $("li.text-filter").hide()
+        },
+        applyFilter: function(e) {
+            var filter = $(e.currentTarget).val().toLowerCase()
+            if (!filter) {
+                $(".template-lozenge").show()
+            } else {
+                _.each($(".template-lozenge"), function(it) {
+                    console.log($(it))
+                    console.log($(it).text())
+                    var viz = $(it).text().toLowerCase().indexOf(filter)>=0
+                    if (viz) 
+                        $(it).show() 
+                    else 
+                        $(it).hide()
+                })
+            }
+        },
+        addTemplateLozenges: function(event) {
+            var that = this
+            _.each(this.catalogApplicationItems, function(item) {
+                that.addTemplateLozenge(that, item)
+            })
+        },
+        addTemplateLozenge: function(that, item) {
+            var $tempel = _.template(CreateStepTemplateEntryHtml, {
+                id: item.id,
+                name: item.name,
+                description: item.description,
+                iconUrl: item.iconUrl
+            })
+            $("#create-step-template-entries", that.$el).append($tempel)
+        },
+        templateClick: function(event) {
+            var $tl = $(event.target).closest(".template-lozenge");
+            var wasSelected = $tl.hasClass("selected")
+            $(".template-lozenge").removeClass("selected")
+            if (!wasSelected) {
+                $tl.addClass("selected")
+                this.selectedTemplateId = $tl.attr('id');
+            } else {
+                this.selectedTemplateId = null;
+            }
+        },
         expandEntity:function (event) {
             
$(event.currentTarget).next().show('fast').delay(1000).prev().hide('slow')
         },
         saveEntityClick:function (event) {
-            this.saveEntity($(event.currentTarget).parent().parent().parent());
+            
this.saveEntity($(event.currentTarget).closest(".editable-entity-group"));
         },
         saveEntity:function ($entityGroup) {
             var that = this
             var name = $('#entity-name',$entityGroup).val()
             var type = $('#entity-type',$entityGroup).val()
-            if (type=="" || !_.contains(that.catalogEntities, type)) {
+            if (type=="" || !_.contains(that.catalogEntityIds, type)) {
                 
$('.entity-info-message',$entityGroup).show('slow').delay(2000).hide('slow')
                 return false
             }
@@ -209,33 +266,42 @@ define([
         },
         getConfigMap:function (root) {
             var map = {}
-            $('.app-add-wizard-create-entity-config',root).each( function 
(index,elt) {
+            $('.app-add-wizard-config-entry',root).each( function (index,elt) {
                 map[$('#key',elt).val()] = $('#value',elt).val()
             })
             return map;
         },
         saveTemplate:function () {
+            var type = this.selectedTemplateId
+            if (type === undefined) return false
+            if (!_.contains(this.catalogApplicationIds, type)) {
+                $('.entity-info-message').show('slow').delay(2000).hide('slow')
+                return false
+            }
+            this.model.set("type", type);
+            return true;
+        },
+        saveAppClass:function () {
             var that = this
-            var tab = $.find('#templateTab')
-            var type = $(tab).find('#entity-type').val()
-            if (!_.contains(this.catalogApplications, type)) {
+            var tab = $.find('#appClassTab')
+            var type = $(tab).find('#app-java-type').val()
+            if (!_.contains(this.catalogApplicationIds, type)) {
                 $('.entity-info-message').show('slow').delay(2000).hide('slow')
                 return false
             }
             this.model.set("type", type);
-            this.model.set("config", this.getConfigMap(tab))
             return true;
         },
-        addEntity:function () {
+        addEntityBox:function () {
             var entity = new Entity.Model
             this.model.addEntity( entity )
-            this.addEntityHtml(this.$('#entitiesAccordionish'), entity)
+            this.addEntityHtml($('#entitiesAccordionish', this.$el), entity)
         },
         addEntityHtml:function (parent, entity) {
             var $entity = _.template(CreateEntityEntryHtml, {})
             var that = this
             parent.append($entity)
-            parent.children().last().find('.entity-type-input').typeahead({ 
source: that.catalogEntities })
+            parent.children().last().find('.entity-type-input').typeahead({ 
source: that.catalogEntityIds })
         },        
         removeEntityClick:function (event) {
             var $entityGroup = 
$(event.currentTarget).parent().parent().parent();
@@ -244,7 +310,7 @@ define([
         },
         
         addConfigRow:function (event) {
-            var $row = _.template(CreateConfigEntryHtml, {})
+            var $row = _.template(EditConfigEntryHtml, {})
             $(event.currentTarget).parent().prev().append($row)
         },
         removeConfigRow:function (event) {
@@ -258,10 +324,10 @@ define([
                 var allokay = true
                 $($.find('.editable-entity-group')).each(
                     function (i,$entityGroup) {
-                        allokay = that.saveEntity($entityGroup) & allokay
+                        allokay = that.saveEntity($($entityGroup)) & allokay
                     })
                 if (!allokay) return false;
-                if (this.model.get("entities").length > 0) {
+                if (this.model.get("entities") && 
this.model.get("entities").length > 0) {
                     this.model.set("type", null);
                     return true;
                 }
@@ -270,7 +336,13 @@ define([
                     this.model.set("entities", []);
                     return true
                 }
+            } else if (tabName=='#appClassTab') {
+                if (this.saveAppClass()) {
+                    this.model.set("entities", []);
+                    return true
+                }
             } else {
+                console.log("NOT IMPLEMENTED YET")
                 // other tabs not implemented yet 
                 // do nothing, show error return false below
             }
@@ -287,7 +359,9 @@ define([
             'click #remove-app-location':'removeLocation',
             'change select':'selection',
             'change option':'selection',
-            'blur #application-name':'updateName'
+            'blur #application-name':'updateName',
+            'click #remove-config':'removeConfigRow',
+            'click #add-config':'addConfigRow'
         },
         template:_.template(DeployHtml),
         locationRowTemplate:_.template(DeployLocationRowHtml),
@@ -355,6 +429,20 @@ define([
             this.model.removeLocationIndex(toBeRemoved)
             this.renderAddedLocations()
         },
+        addConfigRow:function (event) {
+            var $row = _.template(EditConfigEntryHtml, {})
+            $(event.currentTarget).parent().prev().append($row)
+        },
+        removeConfigRow:function (event) {
+            $(event.currentTarget).parent().remove()
+        },
+        getConfigMap:function() {
+            var map = {}
+            $('.app-add-wizard-config-entry').each( function (index,elt) {
+                map[$('#key',elt).val()] = $('#value',elt).val()
+            })
+            return map;
+        },
         selection:function (event) {
                var url = $(event.currentTarget).val();
                var loc = this.locations.find(function (candidate) {
@@ -364,10 +452,15 @@ define([
                                loc.getLinkByName("self"))
         },
         updateName:function () {
-            this.model.set("name", this.$('#application-name').val())
+            var name = this.$('#application-name').val()
+            if (name)
+                this.model.set("name", name)
+            else
+                this.model.set("name", "")
         },
         validate:function () {
-            if (this.model.get("name") !== "" && 
this.model.get("locations").length !== 0) {
+            this.model.set("config", this.getConfigMap())
+            if (this.model.get("locations").length !== 0) {
                 return true
             }
             this.$('div.info-message').show('slow').delay(2000).hide('slow')
@@ -385,15 +478,24 @@ define([
             this.model.off("change", this.render)
         },
         render:function () {
+            if (!this.model.get("entities") || 
this.model.get("entities").length==0) {
+                delete this.model.attributes["entities"]
+            }
+            if (!this.model.get("name"))
+                delete this.model.attributes["name"]
+            if (!this.model.get("config") || 
_.keys(this.model.get("config")).length==0) {
+                delete this.model.attributes["config"]
+            }
+
             this.$('#app-summary').val(FormatJSON(this.model.toJSON()))
             this.delegateEvents()
             return this
         },
         validate:function () {
-            if (this.model.get("name") != ""
-                && this.model.get("locations").length > 0
-                && (this.model.get("type")!=null || 
-                               this.model.get("entities").length > 0)) {
+            // need locations, and type or entities
+            if ((this.model.get("locations").length > 0) && 
+                (this.model.get("type")!=null || 
+                       this.model.getEntities().length > 0)) {
                 return true
             }
             this.showFailure()

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/c299b335/usage/jsgui/src/main/webapp/assets/js/view/application-tree.js
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/js/view/application-tree.js 
b/usage/jsgui/src/main/webapp/assets/js/view/application-tree.js
index e5dd18e..5bde0df 100644
--- a/usage/jsgui/src/main/webapp/assets/js/view/application-tree.js
+++ b/usage/jsgui/src/main/webapp/assets/js/view/application-tree.js
@@ -123,8 +123,6 @@ define([
                     model:entitySummary,
                     application:app
                 })
-                console.log("loading")
-                console.log(that.detailsView.render().el)
                 $("div#details").html(that.detailsView.render().el)
                 // preserve the tab selected before
                 $("div#details").find("a[href=\"#"+whichTab+"\"]").tab('show')

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/c299b335/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 a31044f..e1f5690 100644
--- a/usage/jsgui/src/main/webapp/assets/js/view/catalog.js
+++ b/usage/jsgui/src/main/webapp/assets/js/view/catalog.js
@@ -42,7 +42,6 @@ define([
             
             var that = this;
             _.defer(function() {
-                console.log($("#applications div.accordion-head"))
                 that.toggleAccordionDiv($("#applications div.accordion-head"), 
false)
                 $("#details-empty").show()
             })
@@ -66,8 +65,8 @@ define([
         },
         renderGenericAccordion: function(accordion, data) {
             accordion.html('')
-            _.each(data, function (id, pos) {
-                accordion.append(this.entryTemplate({type:id, id:id}));
+            _.each(data, function (item, pos) {
+                accordion.append(this.entryTemplate({type:item.type, 
id:item.id}));
             }, this)
             accordion.find("div[id='"+this.activeItem+"']").addClass('active')
         },

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/c299b335/usage/jsgui/src/main/webapp/assets/js/view/home.js
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/js/view/home.js 
b/usage/jsgui/src/main/webapp/assets/js/view/home.js
index e73e58d..88a748a 100644
--- a/usage/jsgui/src/main/webapp/assets/js/view/home.js
+++ b/usage/jsgui/src/main/webapp/assets/js/view/home.js
@@ -57,7 +57,7 @@ define([
             }
             
             this.callPeriodically(function() {
-               //that.refresh(that);                           
+               that.refresh(that);                     
             }, 5000)
             this.refresh(this)
         },
@@ -115,14 +115,16 @@ define([
                 this._modal.close()
             }
             var that = this;
-            var wizard = new AppAddWizard({appRouter:this.options.appRouter})
-            this._modal = wizard
-            this.$("#modal-container").html(wizard.render().el)
-            this.$("#modal-container .modal")
-                .on("hidden",function () {
-                    wizard.close()
-                    that.refresh(that)
-                }).modal('show')
+            if (!this.options.offline) {
+                var wizard = new 
AppAddWizard({appRouter:this.options.appRouter})
+                this._modal = wizard
+                this.$("#modal-container").html(wizard.render().el)
+                this.$("#modal-container .modal")
+                    .on("hidden",function () {
+                        wizard.close()
+                        that.refresh(that)
+                    }).modal('show')
+            }
         },
 
         deleteApplication:function (event) {

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/c299b335/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/create-config-entry.html
----------------------------------------------------------------------
diff --git 
a/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/create-config-entry.html
 
b/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/create-config-entry.html
deleted file mode 100644
index f4a1779..0000000
--- 
a/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/create-config-entry.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<div class="controls app-add-wizard-create-entity-config">
-       <input id="key" type="text" class="input-medium" name="key" 
placeholder="key"> 
-       <input id="value" type="text" class="input-medium" name="value" 
placeholder="value">
-       
-       <button id="remove-config" class="btn btn-info btn-mini" type="button">
-               <i class="icon-minus-sign"></i>
-       </button>
-</div>

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/c299b335/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/create-entity-entry.html
----------------------------------------------------------------------
diff --git 
a/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/create-entity-entry.html
 
b/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/create-entity-entry.html
index df12216..51e6aff 100644
--- 
a/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/create-entity-entry.html
+++ 
b/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/create-entity-entry.html
@@ -37,7 +37,7 @@
             </div>
                        <div>
                                <button id="add-config" class="btn btn-mini 
btn-info">
-                                   Add Config Key</button>
+                                   Add Configuration</button>
                        </div>
                </div>
        </div>

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/c299b335/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/create-step-template-entry.html
----------------------------------------------------------------------
diff --git 
a/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/create-step-template-entry.html
 
b/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/create-step-template-entry.html
new file mode 100644
index 0000000..da52845
--- /dev/null
+++ 
b/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/create-step-template-entry.html
@@ -0,0 +1,13 @@
+<div class="template-lozenge frame" id="<%= id %>">
+    <% if (iconUrl) { %>
+    <div class="icon">
+        <img src="<%= iconUrl %>" alt="(icon)" />
+    </div>
+    <% } %>
+    <div class="blurb">
+        <div class="title"><%= name %></div>
+        <div class="description">
+            <%= description ? description : "" %>
+        </div>
+    </div>
+</div>

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/c299b335/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/create.html
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/create.html 
b/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/create.html
index 0ae2c0a..d13a486 100644
--- a/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/create.html
+++ b/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/create.html
@@ -15,32 +15,19 @@
                                <li><a tabindex="-1" data-toggle="tab" 
href="#xmlTab">XML</a></li>
                                <li class="divider"></li>
                                <li><a tabindex="-1" data-toggle="tab" 
href="#groovyTab">Groovy</a></li>
-                               <li class="divider"></li>
+                               <li><a tabindex="-1" data-toggle="tab" 
href="#appClassTab">App Class</a></li>
                                <li><a tabindex="-1" data-toggle="tab" 
href="#uploadTab">JAR</a></li>
-                       </ul></li>
+                       </ul>
+               </li>
+          <li class="text-filter pull-right"><input type="text"/></li>
        </ul>
 
-  <div class="tab-content">
+ <div class="tab-content-scroller">
+ <div class="tab-content">
+ 
   <div class="tab-pane active" id="templateTab">
-  
-        <div class="control-group">
-            <div class="app-add-wizard-create-entity-label-newline">Type</div>
-            <div class="controls app-type">
-                <input id="entity-type" type="text" name="type" 
class="input-large app-add-wizard-create-entity-input application-type-input" 
placeholder="type">
-            </div>
-        </div>
-
-        <div class="control-group">
-            <div 
class="app-add-wizard-create-entity-label-newline">Configuration</div>
-            <div class="controls">
-            </div>
-            <div>
-                <button id="add-config" class="btn btn-mini btn-info">
-                    Add Config Key</button>
-            </div>
-        </div>
+    <div id="create-step-template-entries"/>
   </div>
-
   
   <div class="tab-pane" id="entitiesTab">
     <div id="entitiesAccordionish"></div>
@@ -59,4 +46,16 @@
   <div class="tab-pane" id="uploadTab">
     <br/><br/><i>coming soon!</i>
   </div>
+  
+  
+  <div class="tab-pane" id="appClassTab">
+        <div class="control-group">
+            <div class="app-add-wizard-create-entity-label-newline">Type</div>
+            <div class="controls app-type">
+                <input id="app-java-type" type="text" name="type" 
class="input-large app-add-wizard-create-entity-input application-type-input" 
placeholder="type">
+            </div>
+        </div>
+  </div>
+  
+ </div></div>
 </div>

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/c299b335/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/deploy.html
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/deploy.html 
b/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/deploy.html
index b69f5ba..b5def12 100644
--- a/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/deploy.html
+++ b/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/deploy.html
@@ -1,28 +1,35 @@
 <!-- New application wizard step 1: set name and locations -->
+<div class="deploy">
 
-<div class="info-message label-message hide">
-        <span class="label-important">Important</span>
-        Name and location must be specified
-</div>
-<div class="info-nolocs-message label-message hide">
-        <span class="label-important">Important</span> 
-        Missing or unconfigured locations
-</div>
+       <div class="info-message label-message hide">
+               <span class="label-important">Important</span> Location must be 
specified
+       </div>
+       <div class="info-nolocs-message label-message hide">
+               <span class="label-important">Important</span> Missing or 
unconfigured locations
+       </div>
 
+    <div id="app-locations" class="control-group">
+        <div class="deploy-label">Locations</div>
+        <div id="selector-container"></div>
+        <button id="add-selector-container" class="btn btn-info btn-mini">
+            Add Additional Location</button>
+    </div>
 
-<div class="control-group">
-    <label for="application-name">Name</label>
+       <div class="control-group">
+               <div class="application-name-label deploy-label">Name 
(optional)</div>
+               <div class="controls">
+                       <input id="application-name" name="name" type="text"
+                               style="width: 80%">
+               </div>
+       </div>
 
-    <div class="controls">
-        <input id="application-name" name="name" type="text" style="width:80%">
-    </div>
-</div>
+       <div class="control-group">
+               <div class="app-add-wizard-create-entity-label-newline 
deploy-label">Configuration</div>
+               <div class="controls"></div>
+               <div>
+                       <button id="add-config" class="btn btn-mini btn-info">
+                        Add Configuration</button>
+               </div>
+       </div>
 
-<div id="app-locations">
-    <div>Locations</div>
-    <div id="selector-container" class="control-group">
-    </div>
-    <button id="add-selector-container" class="btn btn-info btn-mini">Add 
Additional Location</button>
 </div>
-
-</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/c299b335/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/edit-config-entry.html
----------------------------------------------------------------------
diff --git 
a/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/edit-config-entry.html 
b/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/edit-config-entry.html
new file mode 100644
index 0000000..366b4d7
--- /dev/null
+++ 
b/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/edit-config-entry.html
@@ -0,0 +1,8 @@
+<div class="controls app-add-wizard-config-entry">
+       <input id="key" type="text" class="input-medium" name="key" 
placeholder="key"> 
+       <input id="value" type="text" class="input-medium" name="value" 
placeholder="value">
+       
+       <button id="remove-config" class="btn btn-info btn-mini" type="button">
+               <i class="icon-minus-sign"></i>
+       </button>
+</div>

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/c299b335/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/preview.html
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/preview.html 
b/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/preview.html
index 3b9642f..a7e5db9 100644
--- a/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/preview.html
+++ b/usage/jsgui/src/main/webapp/assets/tpl/app-add-wizard/preview.html
@@ -1,10 +1,13 @@
 <!-- New application wizard step 3: summary and submit the app -->
-<div>
-    <h3>Application Preview</h3>
-    <textarea id="app-summary" readonly="readonly" rows="16" 
style="width:100%;"></textarea>
-</div>
-<dl class="dl-horizontal"></dl>
-<div class="info-message hide label-message">
-        <span class="label-important">ERROR</span>
-        Invalid spec or server failure
-</div>
+<div class="preview">
+       <div>
+               <h3>Application Preview</h3>
+               <textarea id="app-summary" readonly="readonly" rows="16"
+                       style="width: 100%;"></textarea>
+       </div>
+       <dl class="dl-horizontal"></dl>
+       <div class="info-message hide label-message">
+               <span class="label-important">ERROR</span> Invalid spec or 
server
+               failure
+       </div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/c299b335/usage/jsgui/src/test/java/brooklyn/rest/jsgui/BrooklynJavascriptGuiLauncherTest.java
----------------------------------------------------------------------
diff --git 
a/usage/jsgui/src/test/java/brooklyn/rest/jsgui/BrooklynJavascriptGuiLauncherTest.java
 
b/usage/jsgui/src/test/java/brooklyn/rest/jsgui/BrooklynJavascriptGuiLauncherTest.java
index fad015e..e751aee 100644
--- 
a/usage/jsgui/src/test/java/brooklyn/rest/jsgui/BrooklynJavascriptGuiLauncherTest.java
+++ 
b/usage/jsgui/src/test/java/brooklyn/rest/jsgui/BrooklynJavascriptGuiLauncherTest.java
@@ -29,7 +29,7 @@ public class BrooklynJavascriptGuiLauncherTest {
     @Test
     public void testJavascriptWithRest() throws Exception {
         server = BrooklynJavascriptGuiLauncher.startJavascriptAndRest();
-        BrooklynRestApiLauncherTest.enableJavaClassPathUrlsForScanning(server);
+        
BrooklynRestApiLauncherTest.forceUseOfDefaultCatalogWithJavaClassPath(server);
         BrooklynRestApiLauncherTest.enableAnyoneLogin(server);
         checkUrlContains("/index.html", "Brooklyn");
         checkUrlContains("/v1/catalog/entities", "Tomcat");

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/c299b335/usage/jsgui/src/test/javascript/specs/model/application-spec.js
----------------------------------------------------------------------
diff --git a/usage/jsgui/src/test/javascript/specs/model/application-spec.js 
b/usage/jsgui/src/test/javascript/specs/model/application-spec.js
index b005112..bb3ef7c 100644
--- a/usage/jsgui/src/test/javascript/specs/model/application-spec.js
+++ b/usage/jsgui/src/test/javascript/specs/model/application-spec.js
@@ -97,12 +97,12 @@ define([
             expect(spec.trigger).toHaveBeenCalled()
         })
 
-        it('does not allow you to add the same entity twice', function () {
+        it('allows you to add the same entity twice', function () {
             var spec = new Application.Spec,
                 entity = new Entity.Model({ name:'test-entity'})
             spec.addEntity(entity)
             spec.addEntity(entity)
-            expect(spec.get("entities").length).toEqual(1)
+            expect(spec.get("entities").length).toEqual(2)
         })
     })
 })

Reply via email to