You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2016/02/01 18:52:52 UTC

[34/51] [abbrv] [partial] brooklyn-ui git commit: move subdir from incubator up a level as it is promoted to its own repo (first non-incubator commit!)

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/18b073a9/brooklyn-ui/src/main/webapp/assets/js/view/application-add-wizard.js
----------------------------------------------------------------------
diff --git a/brooklyn-ui/src/main/webapp/assets/js/view/application-add-wizard.js b/brooklyn-ui/src/main/webapp/assets/js/view/application-add-wizard.js
deleted file mode 100644
index 2c4f012..0000000
--- a/brooklyn-ui/src/main/webapp/assets/js/view/application-add-wizard.js
+++ /dev/null
@@ -1,838 +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.
-*/
-/**
- * Builds a Twitter Bootstrap modal as the framework for a Wizard.
- * Also creates an empty Application model.
- */
-define([
-    "underscore", "jquery", "backbone", "brooklyn-utils", "js-yaml",
-    "model/entity", "model/application", "model/location", "model/catalog-application",
-    "text!tpl/app-add-wizard/modal-wizard.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/required-config-entry.html",
-    "text!tpl/app-add-wizard/edit-config-entry.html",
-    "text!tpl/app-add-wizard/deploy.html",
-    "text!tpl/app-add-wizard/deploy-version-option.html",
-    "text!tpl/app-add-wizard/deploy-location-row.html",
-    "text!tpl/app-add-wizard/deploy-location-option.html",
-    "bootstrap"
-    
-], function (_, $, Backbone, Util, JsYaml, Entity, Application, Location, CatalogApplication,
-             ModalHtml, CreateHtml, CreateStepTemplateEntryHtml, CreateEntityEntryHtml,
-             RequiredConfigEntryHtml, EditConfigEntryHtml, DeployHtml,
-             DeployVersionOptionHtml, DeployLocationRowHtml, DeployLocationOptionHtml
-) {
-
-    /** Special ID to indicate that no locations will be provided when starting the server. */
-    var NO_LOCATION_INDICATOR = "__NONE__";
-
-    function setVisibility(obj, isVisible) {
-        if (isVisible) obj.show();
-        else obj.hide();
-    }
-
-    function setEnablement(obj, isEnabled) {
-        obj.attr("disabled", !isEnabled)
-    }
-    
-    /** converts old-style spec with "entities" to camp-style spec with services */
-    function oldSpecToCamp(spec) {
-        var services;
-        if (spec.type) {
-            services = [entityToCamp({type: spec.type, version: spec.version, config: spec.config})];
-        } else if (spec.entities) {
-            services = [];
-            var entities = spec.entities;
-            for (var i = 0; i < entities.length; i++) {
-                services.push(entityToCamp(entities[i]));
-            }
-        }
-        var result = {};
-        if (spec.name) result.name = spec.name;
-        if (spec.locations) {
-          if (spec.locations.length>1)
-            result.locations = spec.locations;
-          else
-            result.location = spec.locations[0];
-        }
-        if (services) result.services = services;
-        // NB: currently nothing else is supported in this spec
-        return result;
-    }
-    function entityToCamp(entity) {
-        var result = {};
-        if (entity.name && (!options || !options.exclude_name)) result.name = entity.name;
-        if (entity.type) result.type = entity.type;
-        if (entity.type && entity.version) result.type += ":" + entity.version;
-        if (entity.config && _.size(entity.config)) result["brooklyn.config"] = entity.config;
-        return result;
-    }
-    function getConvertedConfigValue(value) {
-        try {
-            return $.parseJSON(value);
-        } catch (e) {
-            return value;
-        }
-    }
-    
-    var ModalWizard = Backbone.View.extend({
-        tagName:'div',
-        className:'modal hide fade',
-        events:{
-            'click #prev_step':'prevStep',
-            'click #next_step':'nextStep',
-            'click #preview_step':'previewStep',
-            'click #finish_step':'finishStep'
-        },
-        template:_.template(ModalHtml),
-        initialize:function () {
-            this.catalog = {}
-            this.catalog.applications = {}
-            this.model = {}
-            this.model.spec = new Application.Spec;
-            this.model.yaml = "";
-            this.model.mode = "template";  // or "yaml" or "other"
-            this.currentStep = 0;
-            this.steps = [
-                          {
-                              step_id:'what-app',
-                              title:'Create Application',
-                              instructions:'Choose or build the application to deploy',
-                              view:new ModalWizard.StepCreate({ model:this.model, wizard: this, catalog: this.catalog })
-                          },
-                          {
-                              // TODO rather than make this another step -- since we now on preview revert to the yaml tab
-                              // this should probably be shown in the catalog tab, replacing the other contents.
-                              step_id:'name-and-locations',
-                              title:'<%= appName %>',
-                              instructions:'Specify the locations to deploy to and any additional configuration',
-                              view:new ModalWizard.StepDeploy({ model:this.model, catalog: this.catalog })
-                          }
-                          ]
-        },
-        beforeClose:function () {
-            // ensure we close the sub-views
-            _.each(this.steps, function (step) {
-                step.view.close()
-            }, this)
-        },
-        render:function () {
-            this.$el.html(this.template({}))
-            this.renderCurrentStep()
-            return this
-        },
-
-        renderCurrentStep:function (callback) {
-            var name = this.model.name || "";
-            this.title = this.$("h3#step_title")
-            this.instructions = this.$("p#step_instructions")
-
-            var currentStepObj = this.steps[this.currentStep]
-            this.title.html(_.template(currentStepObj.title)({appName: name}));
-            this.instructions.html(currentStepObj.instructions)
-            this.currentView = currentStepObj.view
-            
-            // delegate to sub-views !!
-            this.currentView.render()
-            this.currentView.updateForState()
-            this.$(".modal-body").replaceWith(this.currentView.el)
-            if (callback) callback(this.currentView);
-
-            this.updateButtonVisibility();
-        },
-        updateButtonVisibility:function () {
-            var currentStepObj = this.steps[this.currentStep]
-            
-            setVisibility(this.$("#prev_step"), (this.currentStep > 0))
-
-            // next shown for first step, but not for yaml
-            var nextVisible = (this.currentStep < 1) && (this.model.mode != "yaml")
-            setVisibility(this.$("#next_step"), nextVisible)
-            
-            // previous shown for step 2 (but again, not yaml)
-            var previewVisible = (this.currentStep == 1) && (this.model.mode != "yaml")
-            setVisibility(this.$("#preview_step"), previewVisible)
-            
-            // now set next/preview enablement
-            if (nextVisible || previewVisible) {
-                var nextEnabled = true;
-                if (this.currentStep==0 && this.model.mode=="template" && currentStepObj && currentStepObj.view) {
-                    // disable if this is template selction (lozenge) view, and nothing is selected
-                    if (! currentStepObj.view.selectedTemplate)
-                        nextEnabled = false;
-                }
-                
-                if (nextVisible)
-                    setEnablement(this.$("#next_step"), nextEnabled)
-                if (previewVisible)
-                    setEnablement(this.$("#preview_step"), nextEnabled)
-            }
-            
-            // finish from config step, preview step, and from first step if yaml tab selected (and valid)
-            var finishVisible = (this.currentStep >= 1)
-            var finishEnabled = finishVisible
-            if (!finishEnabled && this.currentStep==0) {
-                if (this.model.mode == "yaml") {
-                    // should do better validation than non-empty
-                    finishVisible = true;
-                    var yaml_code = this.$("#yaml_code").val()
-                    if (yaml_code) {
-                        finishEnabled = true;
-                    }
-                }
-            }
-            setVisibility(this.$("#finish_step"), finishVisible)
-            setEnablement(this.$("#finish_step"), finishEnabled)
-        },
-        
-        submitApplication:function (event) {
-            var that = this
-            var $modal = $('.add-app #modal-container .modal')
-            $modal.fadeTo(500,0.5);
-            
-            var yaml;
-            if (this.model.mode == "yaml") {
-                yaml = this.model.yaml;
-            } else {
-                // Drop any "None" locations.
-                this.model.spec.pruneLocations();
-                yaml = JsYaml.safeDump(oldSpecToCamp(this.model.spec.toJSON()));
-            }
-
-            $.ajax({
-                url:'/v1/applications',
-                type:'post',
-                contentType:'application/yaml',
-                processData:false,
-                data:yaml,
-                success:function (data) {
-                    that.onSubmissionComplete(true, data, $modal)
-                },
-                error:function (data) {
-                    that.onSubmissionComplete(false, data, $modal)
-                }
-            });
-
-            return false
-        },
-        onSubmissionComplete: function(succeeded, data, $modal) {
-            var that = this;
-            if (succeeded) {
-                $modal.modal('hide')
-                $modal.fadeTo(500,1);
-                if (that.options.callback) that.options.callback();             
-            } else {
-                log("ERROR submitting application: "+data.responseText);
-                var response, summary="Server responded with an error";
-                try {
-                    if (data.responseText) {
-                        response = JSON.parse(data.responseText)
-                        if (response) {
-                            summary = response.message;
-                        } 
-                    }
-                } catch (e) {
-                    summary = data.responseText;
-                }
-                that.$el.fadeTo(100,1).delay(200).fadeTo(200,0.2).delay(200).fadeTo(200,1);
-                that.steps[that.currentStep].view.showFailure(summary)
-            }
-        },
-
-        prevStep:function () {
-            this.currentStep -= 1;
-            this.renderCurrentStep();
-        },
-        nextStep:function () {
-            if (this.currentStep == 0) {
-                if (this.currentView.validate()) {
-                    var yaml = (this.currentView && this.currentView.selectedTemplate && this.currentView.selectedTemplate.yaml);
-                    if (yaml) {
-                        try {
-                            yaml = JsYaml.safeLoad(yaml);
-                            hasLocation = yaml.location || yaml.locations;
-                            if (!hasLocation) {
-                              // look for locations defined in locations
-                              svcs = yaml.services;
-                              if (svcs) {
-                                for (svcI in svcs) {
-                                  if (svcs[svcI].location || svcs[svcI].locations) {
-                                    hasLocation = true;
-                                    break;
-                                  }
-                                }
-                              }
-                            }
-                            yaml = (hasLocation ? true : false);
-                        } catch (e) {
-                            log("Warning: could not parse yaml template")
-                            log(yaml);
-                            yaml = false;
-                        }
-                    }
-                    if (yaml) {
-                        // it's a yaml catalog template which includes a location, show the yaml tab
-           	            $("ul#app-add-wizard-create-tab").find("a[href='#yamlTab']").tab('show');
-                        $("#yaml_code").setCaretToStart();
-                    } else {
-                        // it's a java catalog template or yaml template without a location, go to wizard
-                        this.currentStep += 1;
-                        this.renderCurrentStep();
-                    }
-                } else {
-                    // the call to validate will have done the showFailure
-                }
-            } else {
-                throw "Unexpected step: "+this.currentStep;
-            }
-        },
-        previewStep:function () {
-            if (this.currentView.validate()) {
-                this.currentStep = 0;
-                var that = this;
-                this.renderCurrentStep(function callback(view) {
-                    // Drop any "None" locations.
-                    that.model.spec.pruneLocations();
-                    $("textarea#yaml_code").val(JsYaml.safeDump(oldSpecToCamp(that.model.spec.toJSON())));
-                    $("ul#app-add-wizard-create-tab").find("a[href='#yamlTab']").tab('show');
-                    $("#yaml_code").setCaretToStart();
-                });
-            } else {
-                // call to validate should showFailure
-            }
-        },
-        finishStep:function () {
-            if (this.currentView.validate()) {
-                this.submitApplication()
-            } else {
-                // call to validate should showFailure
-            }
-        }
-    })
-    
-    // Note: this does not restore values on a back click; setting type and entity type+name is easy,
-    // but relevant config lines is a little bit more tedious
-    ModalWizard.StepCreate = Backbone.View.extend({
-        className:'modal-body',
-        events:{
-            '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 .template-lozenge':'templateClick',
-            'keyup .text-filter input':'applyFilter',
-            'change .text-filter input':'applyFilter',
-            'paste .text-filter input':'applyFilter',
-            'keyup #yaml_code':'onYamlCodeChange',
-            'change #yaml_code':'onYamlCodeChange',
-            'paste #yaml_code':'onYamlCodeChange',
-            'shown a[data-toggle="tab"]':'onTabChange',
-            'click #templateTab #catalog-add':'switchToCatalogAdd',
-            'click #templateTab #catalog-yaml':'showYamlTab'
-        },
-        template:_.template(CreateHtml),
-        wizard: null,
-        initialize:function () {
-            var self = this
-            self.catalogEntityIds = []
-
-            this.$el.html(this.template({}))
-
-            // for building from entities
-            this.addEntityBox()
-
-            // TODO: Make into models, allow options to override, then pass in in test
-            // with overrridden url. Can then think about fixing tests in application-add-wizard-spec.js.
-            $.get('/v1/catalog/entities', {}, function (result) {
-                self.catalogEntityItems = result
-                self.catalogEntityIds = _.map(result, function(item) { return item.id })
-                self.$(".entity-type-input").typeahead().data('typeahead').source = self.catalogEntityIds
-            })
-            this.options.catalog.applications = new CatalogApplication.Collection();
-            this.options.catalog.applications.fetch({
-                data: $.param({
-                    allVersions: true
-                }),
-                success: function (collection, response, options) {
-                    self.$("#appClassTab .application-type-input").typeahead().data('typeahead').source = collection.getTypes();
-                    $('#catalog-applications-throbber').hide();
-                    $('#catalog-applications-empty').hide();
-                    if (collection.size() > 0) {
-                        self.addTemplateLozenges()
-                    } else {
-                        $('#catalog-applications-empty').show();
-                        self.showYamlTab();
-                    }
-                }
-            });
-        },
-        renderConfiguredEntities:function () {
-            var $configuredEntities = this.$('#entitiesAccordionish').empty()
-            var that = this
-            if (this.model.spec.get("entities") && this.model.spec.get("entities").length > 0) {
-                _.each(this.model.spec.get("entities"), function (entity) {
-                    that.addEntityHtml($configuredEntities, entity)
-                })
-            }
-        },
-        updateForState: function () {},
-        render:function () {
-            this.renderConfiguredEntities()
-            this.delegateEvents()
-            return this
-        },
-        onTabChange: function(e) {
-            var tabText = $(e.target).text();
-            if (tabText=="Catalog") {
-                $("li.text-filter").show()
-            } else {
-                $("li.text-filter").hide()
-            }
-
-            if (tabText=="YAML") {
-                this.model.mode = "yaml";
-            } else if (tabText=="Template") {
-                this.model.mode = "template";
-            } else {
-                this.model.mode = "other";
-            }
-
-            if (this.options.wizard)
-                this.options.wizard.updateButtonVisibility();
-        },
-        onYamlCodeChange: function() {
-            if (this.options.wizard)
-                this.options.wizard.updateButtonVisibility();
-        },
-        switchToCatalogAdd: function() {
-            var $modal = $('.add-app #modal-container .modal')
-            $modal.modal('hide');
-            window.location.href="#v1/catalog/new";
-        },
-        showYamlTab: function() {
-            $("ul#app-add-wizard-create-tab").find("a[href='#yamlTab']").tab('show')
-            $("#yaml_code").focus();
-        },
-        applyFilter: function(e) {
-            var filter = $(e.currentTarget).val().toLowerCase()
-            if (!filter) {
-                $(".template-lozenge").show()
-            } else {
-                _.each($(".template-lozenge"), function(it) {
-                    var viz = $(it).text().toLowerCase().indexOf(filter)>=0
-                    if (viz)
-                        $(it).show()
-                    else
-                        $(it).hide()
-                })
-            }
-        },
-        addTemplateLozenges: function(event) {
-            var that = this
-            _.each(this.options.catalog.applications.getDistinctApplications(), function(item) {
-                that.addTemplateLozenge(that, item[0])
-            })
-        },
-        addTemplateLozenge: function(that, item) {
-            var $tempel = _.template(CreateStepTemplateEntryHtml, {
-                id: item.get('id'),
-                type: item.get('type'),
-                name: item.get('name') || item.get('id'),
-                description: item.get('description'),
-                planYaml:  item.get('planYaml'),
-                iconUrl: item.get('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.selectedTemplate = {
-                    id: $tl.attr('id'),
-                    type: $tl.data('type'),
-                    name: $tl.data("name"),
-                    yaml: $tl.data("yaml"),
-                };
-                if (this.selectedTemplate.yaml) {
-                    $("textarea#yaml_code").val(this.selectedTemplate.yaml);
-                } else {
-                    $("textarea#yaml_code").val("services:\n- type: "+this.selectedTemplate.type);
-                }
-            } else {
-                this.selectedTemplate = null;
-            }
-
-            if (this.options.wizard)
-                this.options.wizard.updateButtonVisibility();
-        },
-        expandEntity:function (event) {
-            $(event.currentTarget).next().show('fast').delay(1000).prev().hide('slow')
-        },
-        saveEntityClick:function (event) {
-            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.catalogEntityIds, type)) {
-                that.showFailure("Missing or invalid type");
-                return false
-            }
-            var saveTarget = this.model.spec.get("entities")[$entityGroup.index()];
-            this.model.spec.set("type", null)
-            saveTarget.name = name
-            saveTarget.type = type
-            saveTarget.config = this.getConfigMap($entityGroup)
-
-            if (name=="") name=type;
-            if (name=="") name="<i>(new entity)</i>";
-            $('#entity-name-header',$entityGroup).html( name )
-            $('.editable-entity-body',$entityGroup).prev().show('fast').next().hide('fast')
-            return true;
-        },
-        getConfigMap:function (root) {
-            var map = {}
-            $('.app-add-wizard-config-entry',root).each( function (index,elt) {
-                var value = getConvertedConfigValue($('#value',elt).val());
-                if (value !== null) {
-                    map[$('#key',elt).val()] = value;
-                }
-            })
-            return map;
-        },
-        saveTemplate:function () {
-            if (!this.selectedTemplate) return false
-            var type = this.selectedTemplate.type;
-            if (!this.options.catalog.applications.hasType(type)) {
-                $('.entity-info-message').show('slow').delay(2000).hide('slow')
-                return false
-            }
-
-            this.model.spec.set("type", type);
-            this.model.name = this.selectedTemplate.name;
-            this.model.catalogEntityData = "LOAD"
-            return true;
-        },
-        saveAppClass:function () {
-            var that = this
-            var tab = $.find('#appClassTab')
-            var type = $(tab).find('#app-java-type').val()
-            if (!this.options.catalog.applications.hasType(type)) {
-                $('.entity-info-message').show('slow').delay(2000).hide('slow')
-                return false
-            }
-            this.model.spec.set("type", type);
-            return true;
-        },
-        addEntityBox:function () {
-            var entity = new Entity.Model
-            this.model.spec.addEntity( 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.catalogEntityIds })
-        },
-        removeEntityClick:function (event) {
-            var $entityGroup = $(event.currentTarget).parent().parent().parent();
-            this.model.spec.removeEntityIndex($entityGroup.index())
-            $entityGroup.remove()
-        },
-
-        addConfigRow:function (event) {
-            var $row = _.template(EditConfigEntryHtml, {})
-            $(event.currentTarget).parent().prev().append($row)
-        },
-        removeConfigRow:function (event) {
-            $(event.currentTarget).parent().remove()
-        },
-
-        validate:function () {
-            var that = this
-            var tabName = $('#app-add-wizard-create-tab li[class="active"] a').attr('href')
-            if (tabName=='#entitiesTab') {
-                delete this.model.spec.attributes["id"]
-                var allokay = true
-                $($.find('.editable-entity-group')).each(
-                    function (i,$entityGroup) {
-                        allokay = that.saveEntity($($entityGroup)) & allokay
-                    })
-                if (!allokay) return false;
-                if (this.model.spec.get("entities") && this.model.spec.get("entities").length > 0) {
-                    this.model.spec.set("type", null);
-                    return true;
-                }
-            } else if (tabName=='#templateTab') {
-                delete this.model.spec.attributes["id"]
-                if (this.saveTemplate()) {
-                    this.model.spec.set("entities", []);
-                    return true
-                }
-            } else if (tabName=='#appClassTab') {
-                delete this.model.spec.attributes["id"]
-                if (this.saveAppClass()) {
-                    this.model.spec.set("entities", []);
-                    return true
-                }
-            } else if (tabName=='#yamlTab') {
-                this.model.yaml = this.$("#yaml_code").val();
-                if (this.model.yaml) {
-                    return true;
-                }
-            } else {
-                console.info("NOT IMPLEMENTED YET")
-                // TODO - other tabs not implemented yet 
-                // do nothing, show error return false below
-            }
-            this.showFailure("Invalid application type/spec");
-            return false
-        },
-
-        showFailure: function(text) {
-            if (!text) text = "Failure performing the specified action";
-            this.$('div.error-message .error-message-text').html(_.escape(text));
-            this.$('div.error-message').slideDown(250).delay(10000).slideUp(500);
-        }
-
-    })
-
-    ModalWizard.StepDeploy = Backbone.View.extend({
-        className:'modal-body',
-
-        events:{
-            'click #add-selector-container':'addLocation',
-            'click #remove-app-location':'removeLocation',
-            'change .select-version': 'selectionVersion',
-            'change .select-location': 'selectionLocation',
-            'blur #application-name':'updateName',
-            'click #remove-config':'removeConfigRow',
-            'click #add-config':'addConfigRow'
-        },
-
-        template:_.template(DeployHtml),
-        versionOptionTemplate:_.template(DeployVersionOptionHtml),
-        locationRowTemplate:_.template(DeployLocationRowHtml),
-        locationOptionTemplate:_.template(DeployLocationOptionHtml),
-
-        initialize:function () {
-            this.model.spec.on("change", this.render, this)
-            this.$el.html(this.template())
-            this.locations = new Location.Collection()
-        },
-        beforeClose:function () {
-            this.model.spec.off("change", this.render)
-        },
-        renderName:function () {
-            this.$('#application-name').val(this.model.spec.get("name"))
-        },
-        renderVersions: function() {
-            var optionTemplate = this.versionOptionTemplate
-                select = this.$('.select-version')
-                container = this.$('#app-versions')
-                defaultVersion = '0.0.0.SNAPSHOT';
-
-            select.empty();
-
-            var versions = this.options.catalog.applications.getVersions(this.model.spec.get('type'));
-            for (var vi = 0; vi < versions.length; vi++) {
-                var version = versions[vi];
-                select.append(optionTemplate({
-                    version: version
-                }));
-            }
-
-            if (versions.length === 1 && versions[0] === defaultVersion) {
-                this.model.spec.set('version', '');
-                container.hide();
-            } else {
-                this.model.spec.set('version', versions[0]);
-                container.show();
-            }
-        },
-        renderAddedLocations:function () {
-            // renders the locations added to the model
-            var rowTemplate = this.locationRowTemplate,
-                optionTemplate = this.locationOptionTemplate,
-                container = this.$("#selector-container-location");
-            container.empty();
-            for (var li = 0; li < this.model.spec.get("locations").length; li++) {
-                var chosenLocation = this.model.spec.get("locations")[li];
-                container.append(rowTemplate({
-                    initialValue: chosenLocation,
-                    rowId: li
-                }));
-            }
-            var $locationOptions = container.find('.select-location');
-            var templated = this.locations.map(function(aLocation) {
-                return optionTemplate({
-                    id: aLocation.id || "",
-                    name: aLocation.getPrettyName()
-                });
-            });
-
-            // insert "none" location
-            $locationOptions.append(templated.join(""));
-            $locationOptions.each(function(i) {
-                var option = $($locationOptions[i]);
-                option.val(option.parent().attr('initialValue'));
-                // Only append dashes if there are any locations
-                if (option.find("option").length > 0) {
-                    option.append("<option disabled>------</option>");
-                }
-                option.append(optionTemplate({
-                    id: NO_LOCATION_INDICATOR,
-                    name: "None"
-                }));
-            });
-        },
-        render:function () {
-            this.delegateEvents()
-            return this
-        },
-        updateForState: function () {
-            var that = this
-            // clear any error message (we are being displayed fresh; if there are errors in the update, we'll show them in code below)
-            this.$('div.error-message').hide();
-            this.renderName()
-            this.renderVersions()
-            this.locations.fetch({
-                success:function () {
-                    if (that.model.spec.get("locations").length==0)
-                        that.addLocation()
-                    else
-                        that.renderAddedLocations()
-                }})
-                
-            if (this.model.catalogEntityData==null) {
-                this.renderStaticConfig(null)
-            } else if (this.model.catalogEntityData=="LOAD") {
-                this.renderStaticConfig("LOADING")
-                $.get('/v1/catalog/entities/'+this.model.spec.get("type"), {}, function (result) {
-                    that.model.catalogEntityData = result
-                    that.renderStaticConfig(that.model.catalogEntityData)
-                })
-            } else {
-                this.renderStaticConfig(this.model.catalogEntityData)
-            }            
-        },
-        addLocation:function () {
-            if (this.locations.models.length>0) {
-                this.model.spec.addLocation(this.locations.models[0].get("id"))
-            } else {
-                // i.e. No location
-                this.model.spec.addLocation(undefined);
-            }
-            this.renderAddedLocations()
-        },
-        removeLocation:function (event) {
-            var toBeRemoved = $(event.currentTarget).parent().attr('rowId')
-            this.model.spec.removeLocationIndex(toBeRemoved)
-            this.renderAddedLocations()
-        },
-        addConfigRow:function (event) {
-            var $row = _.template(EditConfigEntryHtml, {})
-            $(event.currentTarget).parent().prev().append($row)
-        },
-        removeConfigRow:function (event) {
-            $(event.currentTarget).parent().parent().remove()
-        },
-        renderStaticConfig:function (catalogEntryItem) {
-            this.$('.config-table').html('')
-            if (catalogEntryItem=="LOADING") {
-                this.$('.required-config-loading').show()
-            } else {
-                var configs = []
-                this.$('.required-config-loading').hide()
-                if (catalogEntryItem!=null && catalogEntryItem.config!=null) {
-                    var that = this
-                    _.each(catalogEntryItem.config, function (cfg) {
-                        if (cfg.priority !== undefined) {
-                            var html = _.template(RequiredConfigEntryHtml, {data:cfg});
-                            that.$('.config-table').append(html)
-                        }
-                    })
-                }
-            }
-        },
-        getConfigMap:function() {
-            var map = {};
-            $('.app-add-wizard-config-entry').each( function (index,elt) {
-                var value = $('#checkboxValue',elt).length ? $('#checkboxValue',elt).is(':checked') :
-                    getConvertedConfigValue($('#value',elt).val());
-                if (value !== null) {
-                    map[$('#key',elt).val()] = value;
-                }
-            })
-            return map;
-        },
-        selectionVersion:function (event) {
-            this.model.spec.set("version", $(event.currentTarget).val())
-        },
-        selectionLocation:function (event) {
-            var loc_id = $(event.currentTarget).val(),
-                isNoneLocation = loc_id === NO_LOCATION_INDICATOR;
-            var locationValid = isNoneLocation || this.locations.find(function (candidate) {
-                return candidate.get("id")==loc_id;
-            });
-            if (!locationValid) {
-                log("invalid location "+loc_id);
-                this.showFailure("Invalid location "+loc_id);
-                this.model.spec.set("locations",[]);
-            } else {
-                var index = $(event.currentTarget).parent().attr('rowId');
-                this.model.spec.setLocationAtIndex(index, isNoneLocation ? undefined : loc_id);
-            }
-        },
-        updateName:function () {
-            var name = this.$('#application-name').val();
-            if (name)
-                this.model.spec.set("name", name);
-            else
-                this.model.spec.set("name", "");
-        },
-        validate:function () {
-            this.model.spec.set("config", this.getConfigMap())
-            if (this.model.spec.get("locations").length !== 0) {
-                return true
-            } else {
-                this.showFailure("A location is required");
-                return false;
-            }
-        },
-        showFailure: function(text) {
-            if (!text) text = "Failure performing the specified action";
-            log("showing error: "+text);
-            this.$('div.error-message .error-message-text').html(_.escape(text));
-            // flash the error, but make sure it goes away (we do not currently have any other logic for hiding this error message)
-            this.$('div.error-message').slideDown(250).delay(10000).slideUp(500);
-        }
-    })
-    
-    return ModalWizard
-})

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/18b073a9/brooklyn-ui/src/main/webapp/assets/js/view/application-explorer.js
----------------------------------------------------------------------
diff --git a/brooklyn-ui/src/main/webapp/assets/js/view/application-explorer.js b/brooklyn-ui/src/main/webapp/assets/js/view/application-explorer.js
deleted file mode 100644
index e9c23bc..0000000
--- a/brooklyn-ui/src/main/webapp/assets/js/view/application-explorer.js
+++ /dev/null
@@ -1,205 +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.
-*/
-/**
- * This should render the main content in the Application Explorer page.
- * Components on this page should be rendered as sub-views.
- * @type {*}
- */
-define([
-    "underscore", "jquery", "backbone", "view/viewutils", 
-    "./application-add-wizard", "model/application", "model/entity-summary", "model/app-tree", "./application-tree",  "./entity-details",
-    "text!tpl/apps/details.html", "text!tpl/apps/entity-not-found.html", "text!tpl/apps/page.html"
-], function (_, $, Backbone, ViewUtils,
-        AppAddWizard, Application, EntitySummary, AppTree, ApplicationTreeView, EntityDetailsView,
-        EntityDetailsEmptyHtml, EntityNotFoundHtml, PageHtml) {
-
-    var ApplicationExplorerView = Backbone.View.extend({
-        tagName:"div",
-        className:"container container-fluid",
-        id:'application-explorer',
-        template:_.template(PageHtml),
-        notFoundTemplate: _.template(EntityNotFoundHtml),
-        events:{
-            'click .application-tree-refresh': 'refreshApplicationsInPlace',
-            'click #add-new-application':'createApplication',
-            'click .delete':'deleteApplication'
-        },
-        initialize: function () {
-            this.$el.html(this.template({}))
-            $(".nav1").removeClass("active");
-            $(".nav1_apps").addClass("active");
-
-            this.treeView = new ApplicationTreeView({
-                collection:this.collection,
-                appRouter:this.options.appRouter
-            })
-            this.treeView.on('entitySelected', function(e) {
-               this.displayEntityId(e.id, e.get('applicationId'), false);
-            }, this);
-            this.$('div#app-tree').html(this.treeView.renderFull().el)
-            this.$('div#details').html(EntityDetailsEmptyHtml);
-
-            ViewUtils.fetchRepeatedlyWithDelay(this, this.collection)
-        },
-        refreshApplicationsInPlace: function() {
-            // fetch without reset sets of change events, which now get handled correctly
-            // (not a full visual recompute, which reset does - both in application-tree.js)
-            this.collection.fetch();
-        },
-        beforeClose: function () {
-            this.collection.off("reset", this.render);
-            this.treeView.close();
-            if (this.detailsView)
-                this.detailsView.close();
-        },
-        show: function(entityId) {
-            var tab = "";
-            var tabDetails = "";
-            if (entityId) {
-                if (entityId[0]=='/') entityId = entityId.substring(1);
-                var slash = entityId.indexOf('/');
-                if (slash>0) {
-                    tab = entityId.substring(slash+1)
-                    entityId = entityId.substring(0, slash);
-                }
-            }
-            if (tab) {
-                var slash = tab.indexOf('/');
-                if (slash>0) {
-                    tabDetails = tab.substring(slash+1)
-                    tab = tab.substring(0, slash);
-                }
-                this.preselectTab(tab, tabDetails);
-            }
-            this.treeView.selectEntity(entityId)
-        },
-        createApplication:function () {
-            var that = this;
-            if (this._modal) {
-                this._modal.close()
-            }
-            var wizard = new AppAddWizard({
-                appRouter:that.options.appRouter,
-                callback:function() { that.refreshApplicationsInPlace() }
-            })
-            this._modal = wizard
-            this.$(".add-app #modal-container").html(wizard.render().el)
-            this.$(".add-app #modal-container .modal")
-                .on("hidden",function () {
-                    wizard.close()
-                }).modal('show')
-        },
-        deleteApplication:function (event) {
-            // call Backbone destroy() which does HTTP DELETE on the model
-            this.collection.get(event.currentTarget['id']).destroy({wait:true})
-        },
-        /**
-         * Causes the tab with the given name to be selected automatically when
-         * the view is next rendered.
-         */
-        preselectTab: function(tab, tabDetails) {
-            this.currentTab = tab;
-            this.currentTabDetails = tabDetails;
-        },
-        showDetails: function(app, entitySummary) {
-            var that = this;
-            ViewUtils.cancelFadeOnceLoaded($("div#details"));
-
-            var whichTab = this.currentTab;
-            if (!whichTab) {
-                whichTab = "summary";
-                if (this.detailsView) {
-                    whichTab = this.detailsView.$el.find(".tab-pane.active").attr("id");
-                    this.detailsView.close();
-                }
-            }
-            if (this.detailsView) {
-                this.detailsView.close();
-            }
-            this.detailsView = new EntityDetailsView({
-                model: entitySummary,
-                application: app,
-                appRouter: this.options.appRouter,
-                preselectTab: whichTab,
-                preselectTabDetails: this.currentTabDetails,
-            });
-
-            this.detailsView.on("entity.expunged", function() {
-                that.preselectTab("summary");
-                var id = that.selectedEntityId;
-                var model = that.collection.get(id);
-                if (model && model.get("parentId")) {
-                    that.displayEntityId(model.get("parentId"));
-                } else if (that.collection) {
-                    that.displayEntityId(that.collection.first().id);
-                } else if (id) {
-                    that.displayEntityNotFound(id);
-                } else {
-                    that.displayEntityNotFound("?");
-                }
-                that.collection.fetch();
-            });
-            this.detailsView.render( $("div#details") );
-        },
-        displayEntityId: function (id, appName, afterLoad) {
-            var that = this;
-            var entityLoadFailed = function() {
-                return that.displayEntityNotFound(id);
-            };
-            if (appName === undefined) {
-                if (!afterLoad) {
-                    // try a reload if given an ID we don't recognise
-                    this.collection.includeEntities([id]);
-                    this.collection.fetch({
-                        success: function() { _.defer(function() { that.displayEntityId(id, appName, true); }); },
-                        error: function() { _.defer(function() { that.displayEntityId(id, appName, true); }); }
-                    });
-                    ViewUtils.fadeToIndicateInitialLoad($("div#details"))
-                    return;
-                } else {
-                    // no such app
-                    entityLoadFailed();
-                    return; 
-                }
-            }
-
-            var app = new Application.Model();
-            var entitySummary = new EntitySummary.Model;
-
-            app.url = "/v1/applications/" + appName;
-            entitySummary.url = "/v1/applications/" + appName + "/entities/" + id;
-
-            // in case the server response time is low, fade out while it refreshes
-            // (since we can't show updated details until we've retrieved app + entity details)
-            ViewUtils.fadeToIndicateInitialLoad($("div#details"));
-
-            $.when(app.fetch(), entitySummary.fetch())
-                .done(function() {
-                    that.showDetails(app, entitySummary);
-                })
-                .fail(entityLoadFailed);
-        },
-        displayEntityNotFound: function(id) {
-            $("div#details").html(this.notFoundTemplate({"id": id}));
-            ViewUtils.cancelFadeOnceLoaded($("div#details"))
-        },
-    })
-
-    return ApplicationExplorerView
-})

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/18b073a9/brooklyn-ui/src/main/webapp/assets/js/view/application-tree.js
----------------------------------------------------------------------
diff --git a/brooklyn-ui/src/main/webapp/assets/js/view/application-tree.js b/brooklyn-ui/src/main/webapp/assets/js/view/application-tree.js
deleted file mode 100644
index 2f7a3d0..0000000
--- a/brooklyn-ui/src/main/webapp/assets/js/view/application-tree.js
+++ /dev/null
@@ -1,367 +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.
-*/
-/**
- * Sub-View to render the Application tree.
- * @type {*}
- */
-define([
-    "underscore", "jquery", "backbone", "view/viewutils",
-    "model/app-tree", "text!tpl/apps/tree-item.html", "text!tpl/apps/tree-empty.html"
-], function (_, $, Backbone, ViewUtils,
-             AppTree, TreeItemHtml, EmptyTreeHtml) {
-
-    var emptyTreeTemplate = _.template(EmptyTreeHtml);
-    var treeItemTemplate = _.template(TreeItemHtml);
-
-    var findAllTreeboxes = function(id, $scope) {
-        return $('.tree-box[data-entity-id="' + id + '"]', $scope);
-    };
-
-    var findRootTreebox = function(id) {
-        return $('.lozenge-app-tree-wrapper').children('.tree-box[data-entity-id="' + id + '"]', this.$el);
-    };
-
-    var findChildTreebox = function(id, $parentTreebox) {
-        return $parentTreebox.children('.node-children').children('.tree-box[data-entity-id="' + id + '"]');
-    };
-
-    var findMasterTreebox = function(id, $scope) {
-        return $('.tree-box[data-entity-id="' + id + '"]:not(.indirect)', $scope);
-    };
-
-    var createEntityTreebox = function(id, name, $domParent, depth, indirect) {
-        // Tildes in sort key force entities with no name to bottom of list (z < ~).
-        var sortKey = (name ? name.toLowerCase() : "~~~") + "     " + id.toLowerCase();
-
-        // Create the wrapper.
-        var $treebox = $(
-                '<div data-entity-id="'+id+'" data-sort-key="'+sortKey+'" data-depth="'+depth+'" ' +
-                'class="tree-box toggler-group' +
-                    (indirect ? " indirect" : "") +
-                    (depth == 0 ? " outer" : " inner " + (depth % 2 ? " depth-odd" : " depth-even")+
-                    (depth == 1 ? " depth-first" : "")) + '">'+
-                '<div class="entity_tree_node_wrapper"></div>'+
-                '<div class="node-children toggler-target hide"></div>'+
-                '</div>');
-
-        // Insert into the passed DOM parent, maintaining sort order relative to siblings: name then id.
-        var placed = false;
-        var contender = $(".toggler-group", $domParent).first();
-        while (contender.length && !placed) {
-            var contenderKey = contender.data("sort-key");
-            if (sortKey < contenderKey) {
-                contender.before($treebox);
-                placed = true;
-            } else {
-                contender = contender.next(".toggler-group", $domParent);
-            }
-        }
-        if (!placed) {
-            $domParent.append($treebox);
-        }
-        return $treebox;
-    };
-
-    var getOrCreateApplicationTreebox = function(id, name, treeView) {
-        var $treebox = findRootTreebox(id);
-        if (!$treebox.length) {
-            var $insertionPoint = $('.lozenge-app-tree-wrapper', treeView.$el);
-            if (!$insertionPoint.length) {
-                // entire view must be created
-                treeView.$el.html(
-                        '<div class="navbar_main_wrapper treeloz">'+
-                        '<div id="tree-list" class="navbar_main treeloz">'+
-                        '<div class="lozenge-app-tree-wrapper">'+
-                        '</div></div></div>');
-                $insertionPoint = $('.lozenge-app-tree-wrapper', treeView.$el);
-            }
-            $treebox = createEntityTreebox(id, name, $insertionPoint, 0, false);
-        }
-        return $treebox;
-    };
-
-    var getOrCreateChildTreebox = function(id, name, isIndirect, $parentTreebox) {
-        var $treebox = findChildTreebox(id, $parentTreebox);
-        if (!$treebox.length) {
-            $treebox = createEntityTreebox(id, name, $parentTreebox.children('.node-children'), $parentTreebox.data("depth") + 1, isIndirect);
-        }
-        return $treebox;
-    };
-
-    var updateTreeboxContent = function(entity, $treebox, treeView) {
-        var $newContent = $(treeView.template({
-            id: entity.get('id'),
-            parentId:  entity.get('parentId'),
-            model: entity,
-            statusIconUrl: ViewUtils.computeStatusIconInfo(entity.get("serviceUp"), entity.get("serviceState")).url,
-            indirect: $treebox.hasClass('indirect'),
-        }));
-
-        var $wrapper = $treebox.children('.entity_tree_node_wrapper');
-
-        // Preserve old display status (just chevron direction at present).
-        if ($wrapper.find('.tree-node-state').hasClass('icon-chevron-down')) {
-            $newContent.find('.tree-node-state').removeClass('icon-chevron-right').addClass('icon-chevron-down');
-        }
-
-        $wrapper.html($newContent);
-        addEventsToNode($treebox, treeView);
-    };
-
-    var addEventsToNode = function($node, treeView) {
-        // show the "light-popup" (expand / expand all / etc) menu
-        // if user hovers for 500ms. surprising there is no option for this (hover delay).
-        // also, annoyingly, clicks around the time the animation starts don't seem to get handled
-        // if the click is in an overlapping reason; this is why we position relative top: 12px in css
-        $('.light-popup', $node).parent().parent().hover(
-                function(parent) {
-                    treeView.cancelHoverTimer();
-                    treeView.hoverTimer = setTimeout(function() {
-                        var menu = $(parent.currentTarget).find('.light-popup');
-                        menu.show();
-                    }, 500);
-                },
-                function(parent) {
-                    treeView.cancelHoverTimer();
-                    $('.light-popup').hide();
-                }
-        );
-    };
-
-    var selectTreebox = function(id, $treebox, treeView) {
-        $('.entity_tree_node_wrapper').removeClass('active');
-        $treebox.children('.entity_tree_node_wrapper').addClass('active');
-
-        var entity = treeView.collection.get(id);
-        if (entity) {
-            treeView.selectedEntityId = id;
-            treeView.trigger('entitySelected', entity);
-        }
-    };
-
-
-    return Backbone.View.extend({
-        template: treeItemTemplate,
-        hoverTimer: null,
-
-        events: {
-            'click span.entity_tree_node .tree-change': 'treeChange',
-            'click span.entity_tree_node': 'nodeClicked'
-        },
-
-        initialize: function() {
-            this.collection.on('add', this.entityAdded, this);
-            this.collection.on('change', this.entityChanged, this);
-            this.collection.on('remove', this.entityRemoved, this);
-            this.collection.on('reset', this.renderFull, this);
-            _.bindAll(this);
-        },
-
-        beforeClose: function() {
-            this.collection.off("reset", this.renderFull);
-        },
-
-        entityAdded: function(entity) {
-            // Called when the full entity model is fetched into our collection, at which time we can replace
-            // the empty contents of any placeholder tree nodes (.tree-box) that were created earlier.
-            // The entity may have multiple 'treebox' views (in the case of group members).
-
-            // If the new entity is an application, we must create its placeholder in the DOM.
-            if (!entity.get('parentId')) {
-                var $treebox = getOrCreateApplicationTreebox(entity.id, entity.get('name'), this);
-
-                // Select the new app if there's no current selection.
-                if (!this.selectedEntityId)
-                    selectTreebox(entity.id, $treebox, this);
-            }
-
-            this.entityChanged(entity);
-        },
-
-        entityChanged: function(entity) {
-            // The entity may have multiple 'treebox' views (in the case of group members).
-            var that = this;
-            findAllTreeboxes(entity.id).each(function() {
-                var $treebox = $(this);
-                updateTreeboxContent(entity, $treebox, that);
-            });
-        },
-
-        entityRemoved: function(entity) {
-            // The entity may have multiple 'treebox' views (in the case of group members).
-            findAllTreeboxes(entity.id, this.$el).remove();
-            // Collection seems sometimes to retain children of the removed node;
-            // not sure why, but that's okay for now.
-            if (this.collection.getApplications().length == 0)
-                this.renderFull();
-        },
-
-        nodeClicked: function(event) {
-            var $treebox = $(event.currentTarget).closest('.tree-box');
-            var id = $treebox.data('entityId');
-            selectTreebox(id, $treebox, this);
-            return false;
-        },
-
-        selectEntity: function(id) {
-            var $treebox = findMasterTreebox(id, this.$el);
-            selectTreebox(id, $treebox, this);
-        },
-
-        renderFull: function() {
-            var that = this;
-            this.$el.empty();
-
-            // Display tree and highlight the selected entity.
-            if (this.collection.getApplications().length == 0) {
-                this.$el.append(emptyTreeTemplate());
-
-            } else {
-                _.each(this.collection.getApplications(), function(appId) {
-                    var entity = that.collection.get(appId);
-                    var $treebox = getOrCreateApplicationTreebox(entity.id, entity.name, that);
-                    updateTreeboxContent(entity, $treebox, that);
-                });
-            }
-
-            // Select the first app if there's no current selection.
-            if (!this.selectedEntityId) {
-                var firstApp = _.first(this.collection.getApplications());
-                if (firstApp)
-                    this.selectEntity(firstApp);
-            }
-            return this;
-        },
-
-        cancelHoverTimer: function() {
-            if (this.hoverTimer != null) {
-                clearTimeout(this.hoverTimer);
-                this.hoverTimer = null;
-            }
-        },
-
-        treeChange: function(event) {
-            var $target = $(event.currentTarget);
-            var $treeBox = $target.closest('.tree-box');
-            if ($target.hasClass('tr-expand')) {
-                this.showChildrenOf($treeBox, false);
-            } else if ($target.hasClass('tr-expand-all')) {
-                this.showChildrenOf($treeBox, true);
-            } else if ($target.hasClass('tr-collapse')) {
-                this.hideChildrenOf($treeBox, false);
-            } else if ($target.hasClass('tr-collapse-all')) {
-                this.hideChildrenOf($treeBox, true);
-            } else {
-                // default - toggle
-                if ($treeBox.children('.node-children').is(':visible')) {
-                    this.hideChildrenOf($treeBox, false);
-                } else {
-                    this.showChildrenOf($treeBox, false);
-                }
-            }
-            // hide the popup menu
-            this.cancelHoverTimer();
-            $('.light-popup').hide();
-            // don't let other events interfere
-            return false;
-        },
-
-        showChildrenOf: function($treeBox, recurse, excludedEntityIds) {
-            excludedEntityIds = excludedEntityIds || [];
-            var idToExpand = $treeBox.data('entityId');
-            var $wrapper = $treeBox.children('.entity_tree_node_wrapper');
-            var $childContainer = $treeBox.children('.node-children');
-            var model = this.collection.get(idToExpand);
-            if (model == null) {
-                // not yet loaded; parallel thread should load
-                return;
-            }
-
-            var that = this;
-            var children = model.get('children'); // entity summaries: {id: ..., name: ...}
-            var renderChildrenAsIndirect = $treeBox.hasClass("indirect");
-            _.each(children, function(child) {
-                var $treebox = getOrCreateChildTreebox(child.id, child.name, renderChildrenAsIndirect, $treeBox);
-                var model = that.collection.get(child.id);
-                if (model) {
-                    updateTreeboxContent(model, $treebox, that);
-                }
-            });
-            var members = model.get('members'); // entity summaries: {id: ..., name: ...}
-            _.each(members, function(member) {
-                var $treebox = getOrCreateChildTreebox(member.id, member.name, true, $treeBox);
-                var model = that.collection.get(member.id);
-                if (model) {
-                    updateTreeboxContent(model, $treebox, that);
-                }
-            });
-
-            // Avoid infinite recursive expansion using a "taboo list" of indirect entities already expanded in this
-            // operation. Example: a group that contains itself or one of its own ancestors. Such cycles can only
-            // originate via "indirect" subordinates.
-            var expandIfNotExcluded = function($treebox, excludedEntityIds, defer) {
-                if ($treebox.hasClass('indirect')) {
-                    var id = $treebox.data('entityId');
-                    if (_.contains(excludedEntityIds, id))
-                        return;
-                    excludedEntityIds.push(id);
-                }
-                var doExpand = function() { that.showChildrenOf($treebox, recurse, excludedEntityIds); };
-                if (defer) _.defer(doExpand);
-                else doExpand();
-            };
-
-            if (this.collection.includeEntities(_.union(children, members))) {
-                // we have to load entities before we can proceed
-                this.collection.fetch({
-                    success: function() {
-                        if (recurse) {
-                            $childContainer.children('.tree-box').each(function () {
-                                expandIfNotExcluded($(this), excludedEntityIds, true);
-                            });
-                        }
-                    }
-                });
-            }
-
-            $childContainer.slideDown(300);
-            $wrapper.find('.tree-node-state').removeClass('icon-chevron-right').addClass('icon-chevron-down');
-            if (recurse) {
-                $childContainer.children('.tree-box').each(function () {
-                    expandIfNotExcluded($(this), excludedEntityIds, false);
-                });
-            }
-        },
-
-        hideChildrenOf: function($treeBox, recurse) {
-            var $wrapper = $treeBox.children('.entity_tree_node_wrapper');
-            var $childContainer = $treeBox.children('.node-children');
-            if (recurse) {
-                var that = this;
-                $childContainer.children('.tree-box').each(function () {
-                    that.hideChildrenOf($(this), recurse);
-                });
-            }
-            $childContainer.slideUp(300);
-            $wrapper.find('.tree-node-state').removeClass('icon-chevron-down').addClass('icon-chevron-right');
-        },
-
-    });
-
-});

http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/18b073a9/brooklyn-ui/src/main/webapp/assets/js/view/catalog.js
----------------------------------------------------------------------
diff --git a/brooklyn-ui/src/main/webapp/assets/js/view/catalog.js b/brooklyn-ui/src/main/webapp/assets/js/view/catalog.js
deleted file mode 100644
index 7d4ab2a..0000000
--- a/brooklyn-ui/src/main/webapp/assets/js/view/catalog.js
+++ /dev/null
@@ -1,613 +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.
-*/
-define([
-    "underscore", "jquery", "backbone", "brooklyn",
-    "model/location", "model/entity",
-    "text!tpl/catalog/page.html",
-    "text!tpl/catalog/details-entity.html",
-    "text!tpl/catalog/details-generic.html",
-    "text!tpl/catalog/details-location.html",
-    "text!tpl/catalog/add-catalog-entry.html",
-    "text!tpl/catalog/add-yaml.html",
-    "text!tpl/catalog/add-location.html",
-    "text!tpl/catalog/nav-entry.html",
-
-    "bootstrap", "jquery-form"
-], function(_, $, Backbone, Brooklyn,
-        Location, Entity,
-        CatalogPageHtml, DetailsEntityHtml, DetailsGenericHtml, LocationDetailsHtml,
-        AddCatalogEntryHtml, AddYamlHtml, 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
-    // catalog' button (handled by the parent of the AIVs) does not apply the 'active' class to
-    // more than one element.
-    var activeDetailsView;
-
-    var CatalogItemDetailsView = Backbone.View.extend({
-
-        events: {
-            "click .delete": "deleteItem"
-        },
-
-        initialize: function() {
-            _.bindAll(this);
-            this.options.template = _.template(this.options.template || DetailsGenericHtml);
-        },
-
-        render: function() {
-            if (!this.options.model) {
-                return this.renderEmpty();
-            } else {
-                return this.renderDetails();
-            }
-        },
-
-        renderEmpty: function(extraMessage) {
-            this.$el.html("<div class='catalog-details'>" +
-                "<h3>Select an entry on the left</h3>" +
-                (extraMessage ? extraMessage : "") +
-                "</div>");
-            return this;
-        },
-
-        renderDetails: function() {
-            var that = this,
-                model = this.options.model,
-                template = this.options.template;
-            var show = function() {
-                // Keep the previously open section open between items. Duplication between
-                // here and setDetailsView, below. This case handles view refreshes from this
-                // view directly (e.g. when indicating an error), below handles keeping the
-                // right thing open when navigating from view to view.
-                var open = this.$(".in").attr("id");
-                var newHtml = $(template({model: model, viewName: that.options.name}));
-                $(newHtml).find("#"+open).addClass("in");
-                that.$el.html(newHtml);
-                // rewire events. previous callbacks are removed automatically.
-                that.delegateEvents()
-            };
-
-            this.activeModel = model;
-            // Load the view with currently available data and refresh once the load is complete.
-            // Only refreshes the view if the model changes and the user hasn't selected another
-            // item while the load was executing.
-            show();
-            model.on("change", function() {
-                if (that.activeModel.cid === model.cid) {
-                    show();
-                }
-            });
-            model.fetch()
-                .fail(function(xhr, textStatus, errorThrown) {
-                    console.log("error loading", model.id, ":", errorThrown);
-                    if (that.activeModel.cid === model.cid) {
-                        model.error = true;
-                        show();
-                    }
-                })
-                // Runs after the change event fires, or after the xhr completes
-                .always(function () {
-                    model.off("change");
-                });
-            return this;
-        },
-
-        deleteItem: function(event) {
-            // Could use wait flag to block removal of model from collection
-            // until server confirms deletion and success handler to perform
-            // removal. Useful if delete fails for e.g. lack of entitlement.
-            var that = this;
-            var displayName = $(event.currentTarget).data("name") || "item";
-            this.activeModel.destroy({
-                success: function() {
-                    that.renderEmpty("Deleted " + displayName);
-                },
-                error: function(info) {
-                    that.renderEmpty("Unable to permanently delete " + displayName+". Deletion is temporary, client-side only.");
-                }
-            });
-        }
-    });
-
-    var AddCatalogEntryView = Backbone.View.extend({
-        template: _.template(AddCatalogEntryHtml),
-        events: {
-            "click .show-context": "showContext"
-        },
-        initialize: function() {
-            _.bindAll(this);
-        },
-        render: function (initialView) {
-            this.$el.html(this.template());
-            if (initialView) {
-                if (initialView == "entity") initialView = "yaml";
-                
-                this.$("[data-context='"+initialView+"']").addClass("active");
-                this.showFormForType(initialView)
-            }
-            return this;
-        },
-        clearWithHtml: function(template) {
-            if (this.contextView) this.contextView.close();
-            this.context = undefined;
-            this.$(".btn").removeClass("active");
-            this.$("#catalog-add-form").html(template);
-        },
-        beforeClose: function () {
-            if (this.contextView) this.contextView.close();
-        },
-        showContext: function(event) {
-            var $event = $(event.currentTarget);
-            var context = $event.data("context");
-            if (this.context !== context) {
-                if (this.contextView) {
-                    this.contextView.close();
-                }
-                this.showFormForType(context)
-            }
-        },
-        showFormForType: function (type) {
-            this.context = type;
-            if (type == "yaml" || type == "entity") {
-                this.contextView = newYamlForm(this, this.options.parent);
-            } else if (type == "location") {
-                this.contextView = newLocationForm(this, this.options.parent);
-            } else if (type !== undefined) {
-                console.log("unknown catalog type " + type);
-                this.showFormForType("yaml");
-                return;
-            }
-            Backbone.history.navigate("/v1/catalog/new/" + type);
-            this.$("#catalog-add-form").html(this.contextView.$el);
-        }
-    });
-
-    function newYamlForm(addView, addViewParent) {
-        return new Brooklyn.view.Form({
-            template: _.template(AddYamlHtml),
-            onSubmit: function (model) {
-                var submitButton = this.$(".catalog-submit-button");
-                // "loading" is an indicator to Bootstrap, not a string to display
-                submitButton.button("loading");
-                var self = this;
-                var options = {
-                    url: "/v1/catalog/",
-                    data: model.get("yaml"),
-                    processData: false,
-                    type: "post"
-                };
-                $.ajax(options)
-                    .done(function (data, status, xhr) {
-                        // Can extract location of new item with:
-                        //model.url = Brooklyn.util.pathOf(xhr.getResponseHeader("Location"));
-                        if (_.size(data)==0) {
-                          addView.clearWithHtml( "No items supplied." );
-                        } else {
-                          addView.clearWithHtml( "Added: "+_.escape(_.keys(data).join(", ")) 
-                            + (_.size(data)==1 ? ". Loading..." : "") );
-                          addViewParent.loadAnyAccordionItem(_.size(data)==1 ? _.keys(data)[0] : undefined);
-                        }
-                    })
-                    .fail(function (xhr, status, error) {
-                        submitButton.button("reset");
-                        self.$(".catalog-save-error")
-                            .removeClass("hide")
-                            .find(".catalog-error-message")
-                            .html(_.escape(Brooklyn.util.extractError(xhr, "Could not add catalog item:\n'n" + error)));
-                    });
-            }
-        });
-    }
-
-    // Could adapt to edit existing locations too.
-    function newLocationForm(addView, addViewParent) {
-        // 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");
-                }
-                var submitButton = this.$(".catalog-submit-button");
-                // "loading" is an indicator to Bootstrap, not a string to display
-                submitButton.button("loading");
-                location.set("config", configKeys);
-                location.save()
-                    .done(function (data) {
-                        addView.clearWithHtml( "Added: "+data.id+". Loading..." ); 
-                        addViewParent.loadAccordionItem("locations", data.id);
-                    })
-                    .fail(function (response) {
-                        submitButton.button("reset");
-                        body.showError(Brooklyn.util.extractError(response));
-                    });
-            }
-        });
-
-        return form;
-    }
-
-    var Catalog = Backbone.Collection.extend({
-        modelX: Backbone.Model.extend({
-          url: function() {
-            return "/v1/catalog/" + this.name + "/" + this.id + "?allVersions=true";
-          }
-        }),
-        initialize: function(models, options) {
-            this.name = options["name"];
-            if (!this.name) {
-                throw new Error("Catalog collection must know its name");
-            }
-            //this.model is a constructor so it shouldn't be _.bind'ed to this
-            //It actually works when a browser provided .bind is used, but the
-            //fallback implementation doesn't support it.
-            var that = this; 
-            var model = this.model.extend({
-              url: function() {
-                return "/v1/catalog/" + that.name + "/" + this.id.split(":").join("/");
-              }
-            });
-            _.bindAll(this);
-            this.model = model;
-        },
-        url: function() {
-            return "/v1/catalog/" + this.name+"?allVersions=true";
-        }
-    });
-
-    /** Use to fill single accordion view list. */
-    var AccordionItemView = Backbone.View.extend({
-        tag: "div",
-        className: "accordion-item",
-        events: {
-            'click .accordion-head': 'toggle',
-            'click .accordion-nav-row': 'showDetails'
-        },
-        bodyTemplate: _.template(
-            "<div class='accordion-head capitalized'><%= name %></div>" +
-            "<div class='accordion-body' style='display: <%= display %>'></div>"),
-
-        initialize: function() {
-            _.bindAll(this);
-            this.name = this.options.name;
-            if (!this.name) {
-                throw new Error("Name should have been given for accordion entry");
-            } else if (!this.options.onItemSelected) {
-                throw new Error("onItemSelected(model, element) callback should have been given for accordion entry");
-            }
-
-            // Generic templates
-            this.template = _.template(this.options.template || EntryHtml);
-
-            // Returns template applied to function arguments. Alter if collection altered.
-            // Will be run in the context of the AccordionItemView.
-            this.entryTemplateArgs = this.options.entryTemplateArgs || function(model, index) {
-                return {type: model.getVersionedAttr("type"), id: model.get("id")};
-            };
-
-            // undefined argument is used for existing model items
-            var collectionModel = this.options.model || Backbone.Model;
-            this.collection = this.options.collection || new Catalog(undefined, {
-                name: this.name,
-                model: collectionModel
-            });
-            // Refreshes entries list when the collection is synced with the server or
-            // any of its members are destroyed.
-            this.collection
-                .on("sync", this.renderEntries)
-                .on("destroy", this.renderEntries);
-            this.refresh();
-        },
-
-        beforeClose: function() {
-            this.collection.off();
-        },
-
-        render: function() {
-            this.$el.html(this.bodyTemplate({
-                name: this.name,
-                display: this.options.autoOpen ? "block" : "none"
-            }));
-            this.renderEntries();
-            return this;
-        },
-
-        singleItemTemplater: function(isChild, model, index) {
-            var args = _.extend({
-                    cid: model.cid,
-                    isChild: isChild,
-                    extraClasses: (activeDetailsView == this.name && model.cid == this.activeCid) ? "active" : ""
-                }, this.entryTemplateArgs(model));
-            return this.template(args);
-        },
-
-        renderEntries: function() {
-            var elements = this.collection.map(_.partial(this.singleItemTemplater, false), this);
-            this.updateContent(elements.join(''));
-        },
-
-        updateContent: function(markup) {
-            this.$(".accordion-body")
-                .empty()
-                .append(markup);
-        },
-
-        refresh: function() {
-            this.collection.fetch();
-        },
-
-        showDetails: function(event) {
-            var $event = $(event.currentTarget);
-            var cid = $event.data("cid");
-            if (activeDetailsView !== this.name || this.activeCid !== cid) {
-                activeDetailsView = this.name;
-                this.activeCid = cid;
-                var model = this.collection.get(cid);
-                Backbone.history.navigate("v1/catalog/" + this.name + "/" + model.id);
-                this.options.onItemSelected(activeDetailsView, model, $event);
-            }
-        },
-
-        toggle: function() {
-            var body = this.$(".accordion-body");
-            var hidden = this.hidden = body.css("display") == "none";
-            if (hidden) {
-                body.removeClass("hide").slideDown('fast');
-            } else {
-                body.slideUp('fast')
-            }
-        },
-
-        show: function() {
-            var body = this.$(".accordion-body");
-            var hidden = this.hidden = body.css("display") == "none";
-            if (hidden) {
-                body.removeClass("hide").slideDown('fast');
-            }
-        }
-    });
-    
-    var AccordionEntityView = AccordionItemView.extend({
-        renderEntries: function() {
-            var symbolicNameFn = function(model) {return model.get("symbolicName")};
-            var groups = this.collection.groupBy(symbolicNameFn);
-            var orderedIds = _.uniq(this.collection.map(symbolicNameFn));
-
-            function getLatestStableVersion(items) {
-                //the server sorts items by descending version, snapshots at the back
-                return items[0];
-            }
-
-            var catalogTree = _.map(orderedIds, function(symbolicName) {
-                var group = groups[symbolicName];
-                var root = getLatestStableVersion(group);
-                var children = _.reject(group, function(model) {return root.id == model.id;});
-                return {root: root, children: children};
-            });
-
-            var templater = function(memo, item, index) {
-                memo.push(this.singleItemTemplater(false, item.root));
-                return memo.concat(_.map(item.children, _.partial(this.singleItemTemplater, true), this));
-            };
-
-            var elements = _.reduce(catalogTree, templater, [], this);
-            this.updateContent(elements.join(''));
-        }
-    });
-
-    // Controls whole page. Parent of accordion items and details view.
-    var CatalogResourceView = Backbone.View.extend({
-        tagName:"div",
-        className:"container container-fluid",
-        entryTemplate:_.template(EntryHtml),
-
-        events: {
-            'click .refresh':'refresh',
-            'click #add-new-thing': 'createNewThing'
-        },
-
-        initialize: function() {
-            $(".nav1").removeClass("active");
-            $(".nav1_catalog").addClass("active");
-            // Important that bind happens before accordion object is created. If it happens after
-            // `this' will not be set correctly for the onItemSelected callbacks.
-            _.bindAll(this);
-            this.accordion = this.options.accordion || {
-                "applications": new AccordionEntityView({
-                    name: "applications",
-                    singular: "application",
-                    onItemSelected: _.partial(this.showCatalogItem, DetailsEntityHtml),
-                    model: Entity.Model,
-                    autoOpen: !this.options.kind || this.options.kind == "applications"
-                }),
-                "entities": new AccordionEntityView({
-                    name: "entities",
-                    singular: "entity",
-                    onItemSelected: _.partial(this.showCatalogItem, DetailsEntityHtml),
-                    model: Entity.Model,
-                    autoOpen: this.options.kind == "entities"
-                }),
-                "policies": new AccordionEntityView({
-                    // TODO needs parsing, and probably its own model
-                    // but cribbing "entity" works for now 
-                    // (and not setting a model can cause errors intermittently)
-                    onItemSelected: _.partial(this.showCatalogItem, DetailsEntityHtml),
-                    name: "policies",
-                    singular: "policy",
-                    model: Entity.Model,
-                    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",
-                    entryTemplateArgs: function (location, index) {
-                        return {
-                            type: location.getIdentifierName(),
-                            id: location.getLinkByName("self")
-                        };
-                    }
-                })
-            };
-        },
-
-        beforeClose: function() {
-            _.invoke(this.accordion, 'close');
-        },
-
-        render: function() {
-            this.$el.html(_.template(CatalogPageHtml, {}));
-            var parent = this.$(".catalog-accordion-parent");
-            _.each(this.accordion, function(child) {
-                parent.append(child.render().$el);
-            });
-            if (this.options.kind === "new") {
-                this.createNewThing(this.options.id);
-            } else if (this.options.kind && this.options.id) {
-                this.loadAccordionItem(this.options.kind, this.options.id)
-            } else {
-                // Show empty details view to start
-                this.setDetailsView(new CatalogItemDetailsView().render());
-            }
-            return this
-        },
-
-        /** Refreshes the contents of each accordion pane */
-        refresh: function() {
-            _.invoke(this.accordion, 'refresh');
-        },
-
-        createNewThing: function (type) {
-            // Discard if it's the jquery event object.
-            if (!_.isString(type)) {
-                type = undefined;
-            }
-            var viewName = "createNewThing";
-            if (!type) {
-                Backbone.history.navigate("/v1/catalog/new");
-            }
-            activeDetailsView = viewName;
-            this.$(".accordion-nav-row").removeClass("active");
-            var newView = new AddCatalogEntryView({
-                parent: this
-            }).render(type);
-            this.setDetailsView(newView);
-        },
-
-        loadAnyAccordionItem: function (id) {
-            this.loadAccordionItem("entities", id);
-            this.loadAccordionItem("applications", id);
-            this.loadAccordionItem("policies", id);
-            this.loadAccordionItem("locations", id);
-        },
-
-        loadAccordionItem: function (kind, id) {
-            if (!this.accordion[kind]) {
-                console.error("No accordion for: " + kind);
-            } else {
-                var accordion = this.accordion[kind];
-                var self = this;
-                // reset is needed because we rely on server's ordering;
-                // without it, server additions are placed at end of list
-                accordion.collection.fetch({reset: true})
-                    .then(function() {
-                        var model = accordion.collection.get(id);
-                        if (!model) {
-                            // if a version is supplied, try it without a version - needed for locations, navigating after deletion
-                            if (id && id.split(":").length>1) {
-                                model = accordion.collection.get( id.split(":")[0] );
-                            }
-                        }
-                        if (!model) {
-                            // if an ID is supplied without a version, look for first matching version (should be newest)
-                            if (id && id.split(":").length==1 && accordion.collection.models) {
-                                model = _.find(accordion.collection.models, function(m) { 
-                                    return m && m.id && m.id.startsWith(id+":");
-                                });
-                            }
-                        }
-                        // TODO could look in collection for any starting with ID
-                        if (model) {
-                            Backbone.history.navigate("/v1/catalog/"+kind+"/"+id);
-                            activeDetailsView = kind;
-                            accordion.activeCid = model.cid;
-                            accordion.options.onItemSelected(kind, model);
-                            accordion.show();
-                        } else {
-                            // catalog item not found, or not found yet (it might be reloaded and another callback will try again)
-                        }
-                    });
-            }
-        },
-
-        showCatalogItem: function(template, viewName, model, $target) {
-            this.$(".accordion-nav-row").removeClass("active");
-            if ($target) {
-                $target.addClass("active");
-            } else {
-                this.$("[data-cid=" + model.cid + "]").addClass("active");
-            }
-            var newView = new CatalogItemDetailsView({
-                model: model,
-                template: template,
-                name: viewName
-            }).render();
-            this.setDetailsView(newView)
-        },
-
-        setDetailsView: function(view) {
-            this.$("#details").html(view.el);
-            if (this.detailsView) {
-                // Try to re-open sections that were previously visible.
-                var openedItem = this.detailsView.$(".in").attr("id");
-                if (openedItem) {
-                    view.$("#" + openedItem).addClass("in");
-                }
-                this.detailsView.close();
-            }
-            this.detailsView = view;
-        }
-    });
-    
-    return CatalogResourceView
-});