diff --git a/jstests/tests/home/test_views.js b/jstests/tests/home/test_views.js index e55ac06cd..95352149f 100644 --- a/jstests/tests/home/test_views.js +++ b/jstests/tests/home/test_views.js @@ -13,15 +13,15 @@ define([ { model: model } ); - assert.ok(view.loading); + assert.ok(model.loading); model.update() .done(function() { view.model = model; - view.loading = false; + model.loading = false; } ) .done(function() { - assert.notOk(view.loading); + assert.notOk(model.loading); }); }); }); diff --git a/remoteappmanager/static/js/home/controller.js b/remoteappmanager/static/js/home/controller.js index b553054db..f06644374 100644 --- a/remoteappmanager/static/js/home/controller.js +++ b/remoteappmanager/static/js/home/controller.js @@ -1,11 +1,9 @@ /*globals: require, console*/ require([ - "urlutils", "home/models", "home/views/application_list_view", "home/views/application_view" ], function( - urlutils, models, application_list_view, application_view) { @@ -15,13 +13,15 @@ require([ // It is only synchronized at initial load. var model = new models.ApplicationListModel(); - var app_list_view = new application_list_view.ApplicationListView(); - var app_view = new application_view.ApplicationView(); - - $.when(model.update()).done(function () { - app_list_view.loading = false; + new application_list_view.ApplicationListView({ // jshint ignore:line + el: '#applist', + data: function() { return { model: model }; } + }); - app_list_view.model = model; - app_view.model = model; + new application_view.ApplicationView({ // jshint ignore:line + el: '#appview', + data: function() { return { model: model }; } }); + + model.update(); }); diff --git a/remoteappmanager/static/js/home/models.js b/remoteappmanager/static/js/home/models.js index d63e2789f..a2177c013 100644 --- a/remoteappmanager/static/js/home/models.js +++ b/remoteappmanager/static/js/home/models.js @@ -1,12 +1,18 @@ define([ - 'jquery', - 'home/configurables', - 'utils', - 'jsapi/v1/resources' -], function ($, configurables, utils, resources) { + "jquery", + "home/configurables", + "jsapi/v1/resources", + "gamodule", + "dialogs" +], function ($, configurables, resources, gamodule, dialogs) { "use strict"; - var Status = utils.Status; + var Status = { + RUNNING: "RUNNING", + STARTING: "STARTING", + STOPPING: "STOPPING", + STOPPED: "STOPPED" + }; var available_applications_info = function () { // Retrieve information from the various applications and @@ -43,6 +49,8 @@ define([ // Should be the index of the selected app_data, // or null if no selection. this.selected_index = null; + + this.loading = true; }; ApplicationListModel.prototype.update = function() { @@ -56,48 +64,62 @@ define([ ).done(function (app_data) { // app_data contains the data retrieved from the remote API - this.app_list = []; + var app_list = []; - // Add the options for some image types - app_data.forEach(function(application_data, data_idx) { - this.app_list[data_idx] = { app_data: application_data }; - - this._update_configurables(data_idx); - this._update_status(data_idx); + // Sort application list by names + app_data.sort(function(app1, app2) { + var app1_name = app1.image.ui_name? app1.image.ui_name: app1.image.name; + var app2_name = app2.image.ui_name? app2.image.ui_name: app2.image.name; + return app1_name < app2_name? -1: 1; + }); - if (this.app_list[data_idx].status === Status.RUNNING) { - this.app_list[data_idx].delayed = false; - } else { - this.app_list[data_idx].delayed = true; - } + // Add the options for some image types + app_data.forEach(function(application_data) { + var app = { + app_data: application_data, + // Default values, will be overwritten + status: Status.STOPPED, + delayed: true, + configurables: [], + is_running: function() {return this.status === Status.RUNNING;}, + is_stopped: function() {return this.status === Status.STOPPED;}, + is_starting: function() {return this.status === Status.STARTING;}, + is_stopping: function() {return this.status === Status.STOPPING;} + }; + + this._update_configurables(app); + this._update_status(app); + + app.delayed = !app.is_running(); + app_list.push(app); }.bind(this)); + + this.app_list = app_list; + this.loading = false; }.bind(this)); }; ApplicationListModel.prototype.update_idx = function(index) { // Refetches and updates the entry at the given index. - var entry = this.app_list[index].app_data; - var mapping_id = entry.mapping_id; + var app = this.app_list[index]; + var mapping_id = app.app_data.mapping_id; return resources.Application.retrieve(mapping_id) .done(function(new_data) { - this.app_list[index].app_data = new_data; + app.app_data = new_data; - this._update_configurables(index); - this._update_status(index); + this._update_configurables(app); + this._update_status(app); }.bind(this)); }; - ApplicationListModel.prototype._update_configurables = function(index) { - // Updates the configurables submodel for a given application index. - var image = this.app_list[index].app_data.image; - + ApplicationListModel.prototype._update_configurables = function(app) { // Contains the submodels for the configurables. // It is a dictionary that maps a supported (by the image) configurable tag // to its client-side model. - this.app_list[index].configurables = []; + app.configurables = []; - image.configurables.forEach(function(tag) { + app.app_data.image.configurables.forEach(function(tag) { // If this returns null, the tag has not been recognized // by the client. skip it and let the server deal with the // missing data, either by using a default or throwing @@ -105,21 +127,67 @@ define([ var ConfigurableCls = configurables.from_tag(tag); if (ConfigurableCls !== null) { - this.app_list[index].configurables.push(new ConfigurableCls()); + app.configurables.push(new ConfigurableCls()); } - }.bind(this)); + }); }; - ApplicationListModel.prototype._update_status = function(index) { - var app_data = this.app_list[index].app_data; - - if (app_data.container === undefined) { - this.app_list[index].status = Status.STOPPED; + ApplicationListModel.prototype._update_status = function(app) { + if (app.app_data.container === undefined) { + app.status = Status.STOPPED; } else { - this.app_list[index].status = Status.RUNNING; + app.status = Status.RUNNING; } }; + ApplicationListModel.prototype.start_application = function() { + var selected_index = this.selected_index; + var current_app = this.app_list[selected_index]; + + current_app.status = Status.STARTING; + current_app.delayed = true; + + var configurables_data = {}; + current_app.configurables.forEach(function(configurable) { + var tag = configurable.tag; + configurables_data[tag] = configurable.as_config_dict(); + }); + + resources.Container.create({ + mapping_id: current_app.app_data.mapping_id, + configurables: configurables_data + }).done(function() { + this.update_idx(selected_index) + .fail(function(error) { + current_app.status = Status.STOPPED; + dialogs.webapi_error_dialog(error); + }); + }.bind(this)).fail(function(error) { + current_app.status = Status.STOPPED; + dialogs.webapi_error_dialog(error); + }); + }; + + ApplicationListModel.prototype.stop_application = function(index) { + var app_stopping = this.app_list[index]; + app_stopping.status = Status.STOPPING; + + var url_id = app_stopping.app_data.container.url_id; + + resources.Container.delete(url_id) + .done(function() { + this.update_idx(index) + .fail(function(error) { + app_stopping.status = Status.STOPPED; + dialogs.webapi_error_dialog(error); + }); + }.bind(this)) + .fail(function(error) { + app_stopping.status = Status.STOPPED; + dialogs.webapi_error_dialog(error); + }); + }; + return { ApplicationListModel: ApplicationListModel }; diff --git a/remoteappmanager/static/js/home/views/application_list_view.js b/remoteappmanager/static/js/home/views/application_list_view.js index fd603bcca..d7336bc85 100644 --- a/remoteappmanager/static/js/home/views/application_list_view.js +++ b/remoteappmanager/static/js/home/views/application_list_view.js @@ -1,49 +1,13 @@ define([ - 'urlutils', 'utils', - "dialogs", '../../components/vue/dist/vue.min', - "jsapi/v1/resources" -], function (urlutils, utils, dialogs, Vue, resources) { +], function (utils, Vue) { 'use strict'; - var Status = utils.Status; - /* Create application_list ViewModel (will next be wrapped in a main ViewModel which will contain the applicationListView and the applicationView) */ var ApplicationListView = Vue.extend({ - el: '#applist', - - data: function() { - return { - loading: true, - model: { app_list: [], selected_index: null } - }; - }, - - methods: { - stop_application: function(index) { - var app_stopping = this.model.app_list[index]; - app_stopping.status = Status.STOPPING; - - var url_id = app_stopping.app_data.container.url_id; - - resources.Container.delete(url_id) - .done(function() { - this.model.update_idx(index) - .fail(function(error) { - app_stopping.status = Status.STOPPED; - dialogs.webapi_error_dialog(error); - }); - }.bind(this)) - .fail(function(error) { - app_stopping.status = Status.STOPPED; - dialogs.webapi_error_dialog(error); - }); - } - }, - filters: utils.filters }); diff --git a/remoteappmanager/static/js/home/views/application_view.js b/remoteappmanager/static/js/home/views/application_view.js index 44431ea1f..cfbf39c9b 100644 --- a/remoteappmanager/static/js/home/views/application_view.js +++ b/remoteappmanager/static/js/home/views/application_view.js @@ -2,26 +2,11 @@ define([ 'jquery', "urlutils", "utils", - "gamodule", - "dialogs", - "home/models", - '../../components/vue/dist/vue.min', - "jsapi/v1/resources" -], function ($, urlutils, utils, gamodule, dialogs, models, Vue, resources) { + '../../components/vue/dist/vue.min' +], function ($, urlutils, utils, Vue) { "use strict"; - var ga = gamodule.init(); - var Status = utils.Status; - var ApplicationView = Vue.extend({ - el: 'div.content-wrapper', - - data: function() { - return { - model: { app_list: [], selected_index: null } - }; - }, - computed: { current_app: function() { return this.model.app_list[this.model.selected_index] || null; @@ -44,39 +29,6 @@ define([ }, methods: { - start_application: function() { - var selected_index = this.model.selected_index; - var current_app = this.current_app; - - current_app.status = Status.STARTING; - current_app.delayed = true; - - var configurables_data = {}; - current_app.configurables.forEach(function(configurable) { - var tag = configurable.tag; - configurables_data[tag] = configurable.as_config_dict(); - }); - - resources.Container.create({ - mapping_id: current_app.app_data.mapping_id, - configurables: configurables_data - }).done(function() { - ga("send", "event", { - eventCategory: "Application", - eventAction: "start", - eventLabel: current_app.app_data.image.name - }); - - this.model.update_idx(selected_index) - .fail(function(error) { - current_app.status = Status.STOPPED; - dialogs.webapi_error_dialog(error); - }); - }.bind(this)).fail(function(error) { - current_app.status = Status.STOPPED; - dialogs.webapi_error_dialog(error); - }); - }, get_iframe_size: function() { return utils.max_iframe_size(); } diff --git a/remoteappmanager/static/js/utils.js b/remoteappmanager/static/js/utils.js index 8c75fb1a5..56bedbef7 100644 --- a/remoteappmanager/static/js/utils.js +++ b/remoteappmanager/static/js/utils.js @@ -46,13 +46,6 @@ define([ return [width, height]; }; - var Status = { - RUNNING: "RUNNING", - STARTING: "STARTING", - STOPPING: "STOPPING", - STOPPED: "STOPPED" - }; - // Temporary: will be registered in Vue globally var filters = { icon_src: function(icon_data) { @@ -66,18 +59,6 @@ define([ }, app_name: function(image) { return image.ui_name? image.ui_name: image.name; - }, - is_starting: function(application) { - return application.status === Status.STARTING; - }, - is_running: function(application) { - return application.status === Status.RUNNING; - }, - is_stopping: function(application) { - return application.status === Status.STOPPING; - }, - is_stopped: function(application) { - return application.status === Status.STOPPED; } }; @@ -85,8 +66,7 @@ define([ all : all, update : update, max_iframe_size: max_iframe_size, - filters: filters, - Status: Status + filters: filters }; }); diff --git a/remoteappmanager/templates/home.html b/remoteappmanager/templates/home.html index 0d6bf4be0..8bce1628d 100644 --- a/remoteappmanager/templates/home.html +++ b/remoteappmanager/templates/home.html @@ -24,12 +24,12 @@ We initialize this element with "display: none" to prevent displaying "No applications found" and the loading spinner at the same time --> -
-