blob: dc8e084e6498ff0ade2af07e1d122ce881f3623e [file] [log] [blame]
/*
* 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
})