| /* |
| * 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. |
| */ |
| /** |
| * Renders the Applications page. From it we create all other application related views. |
| */ |
| |
| define([ |
| "jquery", "underscore", "backbone", |
| "view/viewutils", |
| "view/application-add-wizard", |
| "view/location-wizard", |
| "view/ha-summary", |
| "model/location", |
| "text!tpl/home/applications.html", |
| "text!tpl/home/summaries.html", |
| "text!tpl/home/app-entry.html", |
| "bootstrap", "brooklyn-utils" |
| ], function ($, _, Backbone, ViewUtils, |
| AppAddWizard, LocationWizard , HASummary, Location, |
| ApplicationsHtml, HomeSummariesHtml, AppEntryHtml) { |
| |
| var HomeView = Backbone.View.extend({ |
| tagName:"div", |
| events:{ |
| 'click #add-new-application':'createApplication', |
| 'click #reload-brooklyn-properties': 'reloadBrooklynProperties', |
| 'click #clear-ha-node-records': 'clearHaNodeRecords', |
| 'click .addApplication': 'createApplication', |
| 'click .addLocation': 'createLocation' |
| }, |
| |
| initialize:function () { |
| var that = this |
| this.$el.html(_.template(ApplicationsHtml, {} )) |
| $(".nav1").removeClass("active"); |
| $(".nav1_home").addClass("active"); |
| this._appViews = {} |
| this.summariesView = new HomeView.HomeSummariesView({ |
| applications:this.collection, |
| locations:this.options.locations |
| }) |
| this.collection.on('reset', this.render, this) |
| this.options.locations.on('reset', this.renderSummaries, this) |
| |
| ViewUtils.fetchRepeatedlyWithDelay(this, this.collection, |
| { fetchOptions: { reset: true }, doitnow: true, |
| /* max is short here so the console becomes usable quickly */ |
| backoffMaxPeriod: 10*1000 }); |
| ViewUtils.fetchRepeatedlyWithDelay(this, this.options.locations, { fetchOptions: { reset: true }, doitnow: true }); |
| |
| var id = $(this.$el).find("#circles-map"); |
| if (this.options.offline) { |
| id.find("#circles-map-message").html("(map off in offline mode)"); |
| } else { |
| requirejs(["googlemaps"], function (GoogleMaps) { |
| _.defer( function() { |
| log("loading google maps") |
| var map = GoogleMaps.addMapToCanvas(id[0], 0, 0, 1); |
| var locatedLocations = new Location.UsageLocated() |
| // googlemaps.js isn't re-loaded during tab-to-tab navigation so we need to reset it each time |
| // the maps is re-drawn to reset the cached set of location markers |
| GoogleMaps.resetCircles() |
| that.updateCircles(that, locatedLocations, GoogleMaps, map) |
| that.callPeriodically("circles", function() { |
| that.updateCircles(that, locatedLocations, GoogleMaps, map) |
| }, 10000) |
| }) |
| }, function (error) { |
| id.find("#circles-map-message").html("(map not available)"); |
| }); |
| } |
| }, |
| |
| updateCircles: function(that, locatedLocations, GoogleMaps, map) { |
| locatedLocations.fetch({success:function() { |
| GoogleMaps.drawCircles(map, locatedLocations.attributes) |
| }}) |
| }, |
| |
| // cleaning code goes here |
| beforeClose:function () { |
| this.haSummaryView.close(); |
| this.collection.off("reset", this.render) |
| this.options.locations.off("reset", this.renderSummaries) |
| _.invoke(this._appViews, "close"); |
| this._appViews = null |
| }, |
| |
| render:function () { |
| this.renderSummaries(); |
| this.renderCollection(); |
| this.renderHighAvailabilitySummary(); |
| return this; |
| }, |
| |
| renderSummaries:function () { |
| this.$('.home-summaries-row').html(this.summariesView.render().el ) |
| }, |
| |
| renderHighAvailabilitySummary: function() { |
| // The HA view handles updates itself. |
| if (!this.haSummaryView) |
| this.haSummaryView = new HASummary({ el: this.$("#ha-summary") }).render(); |
| }, |
| |
| renderCollection:function () { |
| var $tableBody = this.$('#applications-table-body').empty() |
| if (this.collection==null) |
| $tableBody.append("<tr><td colspan='3'><i>No data available</i></td></tr>"); |
| else if (this.collection.isEmpty()) |
| $tableBody.append("<tr><td colspan='3'><i>No applications deployed</i></td></tr>"); |
| else this.collection.each(function (app) { |
| var appView = new HomeView.AppEntryView({model:app}) |
| if (this._appViews[app.cid]) { |
| // if the application has a view destroy it |
| this._appViews[app.cid].close() |
| } |
| this._appViews[app.cid] = appView |
| $tableBody.append(appView.render().el) |
| }, this) |
| }, |
| |
| createApplication:function () { |
| if (this._modal) { |
| this._modal.close() |
| } |
| var that = this; |
| if (this.options.offline || (this.options.cautionOverlay && this.options.cautionOverlay.warningActive)) { |
| // don't show wizard |
| } else { |
| var wizard = new AppAddWizard({appRouter:this.options.appRouter}) |
| this._modal = wizard |
| this.$(".add-app #modal-container").html(wizard.render().el) |
| this.$(".add-app #modal-container .modal") |
| .on("hidden",function () { |
| wizard.close() |
| that.collection.fetch({reset:true}); |
| }).modal('show') |
| } |
| }, |
| |
| createLocation:function () { |
| if (this._modal) { |
| this._modal.close() |
| } |
| var that = this; |
| if (this.options.offline || (this.options.cautionOverlay && this.options.cautionOverlay.warningActive)) { |
| // don't show wizard |
| } else { |
| this._modal = new LocationWizard({ |
| onLocationCreated: function(wizard, data) { |
| that.options.locations.fetch({reset:true}); |
| }, |
| onFinish: function(wizard) { |
| that.$(".add-app #modal-container .modal").modal('hide'); |
| }, |
| isModal: true |
| }); |
| this.$(".add-app #modal-container").html(this._modal.render().el); |
| this.$(".add-app #modal-container .modal") |
| .on("hidden",function () { |
| that._modal.close(); |
| that.options.locations.fetch({reset:true}); |
| }).modal('show'); |
| } |
| }, |
| |
| reloadBrooklynProperties: function() { |
| var self = this; |
| // indicate submitted |
| self.$('#reload-brooklyn-properties-indicator').show(); |
| $.ajax({ |
| type: "POST", |
| url: "/v1/server/properties/reload", |
| contentType: "application/json", |
| success: function() { |
| console.log("reloaded brooklyn properties"); |
| self.options.locations.fetch(); |
| // clear submitted indicator |
| setTimeout(function() { self.$('#reload-brooklyn-properties-indicator').hide(); }, 250); |
| }, |
| error: function(data) { |
| // TODO render the error better than poor-man's flashing |
| // (would just be connection error -- with timeout=0 we get a task even for invalid input) |
| self.$el.fadeTo(100,1).delay(200).fadeTo(200,0.2).delay(200).fadeTo(200,1); |
| self.$('#reload-brooklyn-properties-indicator').hide(); |
| console.error("ERROR reloading brooklyn properties"); |
| console.debug(data); |
| } |
| }); |
| }, |
| |
| clearHaNodeRecords: function() { |
| var self = this; |
| // indicate submitted |
| self.$('#clear-ha-node-records-indicator').show(); |
| $.ajax({ |
| type: "POST", |
| url: "/v1/server/ha/states/clear", |
| contentType: "application/json", |
| success: function() { |
| console.log("cleared HA node records"); |
| self.haSummaryView.updateNow(); |
| // clear submitted indicator |
| setTimeout(function() { self.$('#clear-ha-node-records-indicator').hide(); }, 250); |
| }, |
| error: function(data) { |
| // TODO render the error better than poor-man's flashing |
| // (would just be connection error -- with timeout=0 we get a task even for invalid input) |
| self.$el.fadeTo(100,1).delay(200).fadeTo(200,0.2).delay(200).fadeTo(200,1); |
| self.$('#clear-ha-node-records-indicator').hide(); |
| console.error("ERROR clearing HA nodes"); |
| console.debug(data); |
| } |
| }); |
| } |
| }) |
| |
| HomeView.HomeSummariesView = Backbone.View.extend({ |
| tagName:'div', |
| template:_.template(HomeSummariesHtml), |
| // no listening needed here; it's done by outer class |
| render:function () { |
| this.$el.html(this.template({ |
| apps:this.options.applications, |
| locations:this.options.locations |
| })) |
| return this |
| }, |
| }) |
| |
| HomeView.AppEntryView = Backbone.View.extend({ |
| tagName:'tr', |
| |
| template:_.template(AppEntryHtml), |
| |
| initialize:function () { |
| this.model.on('change', this.render, this) |
| this.model.on('destroy', this.close, this) |
| }, |
| render:function () { |
| this.$el.html(this.template({ |
| cid:this.model.cid, |
| link:this.model.getLinkByName("self"), |
| name:this.model.getSpec().get("name"), |
| status:this.model.get("status") |
| })) |
| return this |
| }, |
| beforeClose:function () { |
| this.off("change", this.render) |
| this.off("destroy", this.close) |
| } |
| }) |
| |
| return HomeView |
| }) |