diff --git a/bower.json b/bower.json index 851068977..6dd59a7be 100644 --- a/bower.json +++ b/bower.json @@ -21,7 +21,6 @@ "datatables.net": "~1.10.12", "datatables.net-dt": "~1.10.12", "admin-lte": "~2.3.11", - "handlebars": "~4.0.5", "underscore": "~1.8.3", "html5shiv": "~3.7.3", "respond": "~1.4.2", diff --git a/jstests/tests.html b/jstests/tests.html index b741dfdc5..a039d5577 100644 --- a/jstests/tests.html +++ b/jstests/tests.html @@ -14,6 +14,7 @@
+
diff --git a/jstests/tests/home/test_application_list_view.js b/jstests/tests/home/test_application_list_view.js new file mode 100644 index 000000000..1ed496d53 --- /dev/null +++ b/jstests/tests/home/test_application_list_view.js @@ -0,0 +1,94 @@ +define([ + "home/models", + "home/views/application_list_view", + "components/vue/dist/vue", + "vue/filters" +], function (models, applicationListView, Vue) { + "use strict"; + + QUnit.module("home.app_list_view"); + QUnit.test("rendering list", function (assert) { + var done = assert.async(); + + var model = new models.ApplicationListModel(); + var appListView = new applicationListView.ApplicationListView({ + data: function() { return { model: model }; } + }).$mount(); + + assert.ok(model.loading); + assert.equal( + appListView.$el.querySelector("#loading-spinner").style.display, + "" + ); + + model.update().done(function() { Vue.nextTick(function() { + assert.equal( + appListView.$el.querySelector("#no-app-msg").style.display, + "none" + ); + assert.equal( + appListView.$el.querySelector("#loading-spinner").style.display, + "none" + ); + assert.equal( + appListView.$el.querySelector("#applistentries").children.length, + model.appList.length + ); + + done(); + })}); + }); + + QUnit.test("rendering nothing in the list", function (assert) { + var done = assert.async(); + + var model = new models.ApplicationListModel(); + var appListView = new applicationListView.ApplicationListView({ + data: function() { return { model: model }; } + }).$mount(); + + model.loading = false; + + Vue.nextTick(function() { + assert.equal( + appListView.$el.querySelector("#no-app-msg").style.display, + "" + ); + assert.equal( + appListView.$el.querySelector("#loading-spinner").style.display, + "none" + ); + assert.equal( + appListView.$el.querySelector("#applistentries").children.length, + 0 + ); + + done(); + }); + }); + + QUnit.test("search form", function (assert) { + var done = assert.async(); + + var model = new models.ApplicationListModel(); + var appListView = new applicationListView.ApplicationListView({ + data: function() { return { model: model }; } + }).$mount(); + + model.update().done(function() { Vue.nextTick(function() { + assert.notEqual(appListView.visibleList.length, 0); + + appListView.searchInput = "heho"; + + Vue.nextTick(function() { + assert.equal(appListView.visibleList.length, 0); + assert.equal( + appListView.$el.querySelector("input[name=q]").value, + "heho" + ); + + done(); + }) + })}); + }); +}); diff --git a/jstests/tests/home/test_application_view.js b/jstests/tests/home/test_application_view.js new file mode 100644 index 000000000..c10703cb3 --- /dev/null +++ b/jstests/tests/home/test_application_view.js @@ -0,0 +1,75 @@ +define([ + "home/models", + "home/views/application_view", + "components/vue/dist/vue", + "vue/filters" +], function (models, applicationView, Vue) { + "use strict"; + + QUnit.module("home.app_view"); + QUnit.test("rendering form", function (assert) { + var done = assert.async(); + + var model = new models.ApplicationListModel(); + var appView = new applicationView.ApplicationView({ + data: function() { return { model: model }; } + }).$mount(); + + model.update().done(function() { Vue.nextTick(function() { + assert.equal(appView.$el.children[0].tagName, 'DIV'); + assert.ok(appView.$el.children[0].classList.contains('row')); + + assert.equal( + appView.$el.querySelector('.box-title').innerHTML, + model.appList[0].appData.image.ui_name + ); + + // Simulate application starting + model.appList[0].status = 'STARTING'; + + assert.equal( + appView.$el.querySelector('.box-title').innerHTML, + model.appList[0].appData.image.ui_name + ); + assert.equal( + appView.$el.querySelector('#app-description').innerHTML, + model.appList[0].appData.image.description + ); + + done(); + })}); + }); + + QUnit.test("rendering iframe", function (assert) { + var done = assert.async(); + + var model = new models.ApplicationListModel(); + var appView = new applicationView.ApplicationView({ + data: function() { return { model: model }; } + }).$mount(); + + model.update().done(function() { + // Simulate application running + model.appList[0].status = 'RUNNING'; + model.appList[0].appData.container = {}; + model.appList[0].appData.container.url_id = 'https://127.0.0.1:1234/'; + + Vue.nextTick(function() { + assert.equal(appView.$el.children[0].tagName, 'IFRAME'); + + // Render form again by selecting the other application which is stopped + model.selectedIndex = 1; + + Vue.nextTick(function() { + console.log(model.appList[1].ui_name) + assert.equal( + appView.$el.querySelector('.box-title').innerHTML, + model.appList[1].appData.image.ui_name + ); + + done(); + }); + }); + }); + }); +}); diff --git a/jstests/tests/home/test_configurables.js b/jstests/tests/home/test_configurables.js index 1d011295c..aec9bcaeb 100644 --- a/jstests/tests/home/test_configurables.js +++ b/jstests/tests/home/test_configurables.js @@ -5,22 +5,21 @@ define([ QUnit.module("home.configurables"); QUnit.test("instantiation", function (assert) { - var resolution_class = configurables.from_tag("resolution"); - var resolution = new resolution_class(); - assert.equal(resolution.tag, "resolution"); - assert.equal(resolution.resolution, "Window"); - - resolution.resolution = "1024x768"; - assert.equal(resolution.as_config_dict().resolution, "1024x768"); + var resolutionConf = new configurables.resolution.model(); + + assert.equal(resolutionConf.tag, "resolution"); + assert.deepEqual(resolutionConf.configDict, { resolution: "Window" }); + assert.notEqual(resolutionConf.asConfigDict().resolution, "Window"); + + resolutionConf.configDict = { resolution: '1280x1024' }; + assert.equal(resolutionConf.asConfigDict().resolution, '1280x1024'); }); - + QUnit.test("view", function (assert) { - var resolution_class = configurables.from_tag("resolution"); - var resolution = new resolution_class(); + var propsData = { configDict: { resolution: "Window" } }; + var component = new configurables.resolution.component({propsData: propsData}).$mount(); - var view = resolution.view(); - assert.notEqual(view.find("select"), null); - assert.equal(view.find("option").length, - resolution.resolution_options.length); + assert.notEqual(component.$el.querySelector("select"), null); + assert.equal(component.$el.querySelector("select").children.length, 5); }); -}); +}); \ No newline at end of file diff --git a/jstests/tests/home/test_models.js b/jstests/tests/home/test_models.js index 78a9c71ee..fe3252dc4 100644 --- a/jstests/tests/home/test_models.js +++ b/jstests/tests/home/test_models.js @@ -1,17 +1,21 @@ define([ - "home/models" + "home/models" ], function (models) { "use strict"; - + QUnit.module("home.models"); QUnit.test("instantiation", function (assert) { var model = new models.ApplicationListModel(); - assert.equal(model.app_data.length, 0); + + assert.equal(model.appList.length, 0); + assert.equal(model.selectedIndex, null); + model.update().done(function() { - assert.equal(model.app_data.length, 2); - assert.equal(model.app_data[0].image.configurables[0], "resolution"); - assert.notEqual(model.configurables[0].resolution, null); - assert.equal(model.configurables[0].resolution.resolution, "Window"); + assert.equal(model.appList.length, 2); + assert.equal(model.selectedIndex, 0); + + assert.equal(model.appList[0].appData.image.configurables[0], "resolution"); + assert.equal(model.appList[0].configurables[0].configDict.resolution, "Window"); }); }); }); diff --git a/jstests/tests/home/test_views.js b/jstests/tests/home/test_views.js deleted file mode 100644 index 79671395f..000000000 --- a/jstests/tests/home/test_views.js +++ /dev/null @@ -1,22 +0,0 @@ -define([ - "home/models", - "home/views/application_list_view", - "jquery" -], function (models, application_list_view, $) { - "use strict"; - QUnit.module("home.views"); - QUnit.test("rendering", function (assert) { - var model = new models.ApplicationListModel(); - var view = new application_list_view.ApplicationListView(model); - model.update() - .done(function() { view.render(); } ) - .done(function() { - var applist = $("#applist"); - assert.equal(applist.children().length, 2); - }) - .done(function() { - model.app_data[0].image.ui_name = "Hello"; - view.update_entry(0); - }); - }); -}); diff --git a/jstests/tests/vue/components/test_ConfirmDialog.js b/jstests/tests/vue/components/test_ConfirmDialog.js index dccdcf8b5..1dcb0ec6f 100644 --- a/jstests/tests/vue/components/test_ConfirmDialog.js +++ b/jstests/tests/vue/components/test_ConfirmDialog.js @@ -4,11 +4,16 @@ define([ "jstests/helpers" ], function (Vue, ConfirmDialog, helpers) { "use strict"; - + QUnit.module("ConfirmDialog"); QUnit.test("rendering", function (assert) { assert.equal(helpers.getRenderedText(ConfirmDialog, { - title: "This is the title" + title: "This is the title", + closeCallback: function() {} }), "This is the title Cancel Ok"); + + assert.equal(helpers.getRenderedText(ConfirmDialog, { + title: "This is the title" + }), "This is the title Ok"); }); }); diff --git a/jstests/testsuite.js b/jstests/testsuite.js index 6fce3be0f..ab7a02729 100644 --- a/jstests/testsuite.js +++ b/jstests/testsuite.js @@ -8,7 +8,6 @@ bootstrap: '../components/bootstrap/js/bootstrap.min', moment: "../components/moment/moment", "jsapi/v1/resources": "../../../jstests/tests/home/mock_jsapi", - handlebars: "../components/handlebars/handlebars.amd.min", underscore: "../components/underscore/underscore-min" }, shim: { @@ -19,24 +18,23 @@ } }); - require([ - "init", + require([ "tests/home/test_configurables.js", "tests/home/test_models.js", - "tests/home/test_views.js", + "tests/home/test_application_list_view.js", + "tests/home/test_application_view.js", "tests/vue/components/test_DataTable.js", "tests/vue/components/test_ConfirmDialog.js", "tests/test_utils.js", "tests/test_analytics.js" - ], function(init) { + ], function() { window.apidata = { base_url: "/", prefix: "/" }; - init.handlebars(); - + QUnit.load(); QUnit.start(); - }); + }); }()); diff --git a/package.json b/package.json index d33976684..44d066c7e 100644 --- a/package.json +++ b/package.json @@ -1,20 +1,19 @@ { - "name": "simphony-remote-deps", - "version": "0.0.0", - "description": "SimPhoNy-remote nodejs dependencies", - "author": "Enthought", - "license": "BSD", - "repository": { - "type": "git", - "url": "https://github.com/simphony-remote/simphony-remote.git" - }, - "dependencies": { - "bower": "*", - "configurable-http-proxy": "git://github.com/jupyterhub/configurable-http-proxy.git#2.0.1" - }, - "devDependencies": { - "jshint": "*", - "node-qunit-phantomjs": "*" - } + "name": "simphony-remote-deps", + "version": "1.2.0", + "description": "SimPhoNy-remote nodejs dependencies", + "author": "Enthought", + "license": "BSD", + "repository": { + "type": "git", + "url": "https://github.com/simphony-remote/simphony-remote.git" + }, + "dependencies": { + "bower": "*", + "configurable-http-proxy": "git://github.com/jupyterhub/configurable-http-proxy.git#2.0.1" + }, + "devDependencies": { + "jshint": "*", + "node-qunit-phantomjs": "*" + } } - diff --git a/remoteappmanager/static/css/remoteappmanager.css b/remoteappmanager/static/css/remoteappmanager.css index 7473fa7b0..f08aef6d6 100644 --- a/remoteappmanager/static/css/remoteappmanager.css +++ b/remoteappmanager/static/css/remoteappmanager.css @@ -9,11 +9,11 @@ body { float: none; } -#applist > li > a > div { +#applistentries > li > a > div { float: left; } -#applist img.app-icon { +#applistentries img.app-icon { position: relative; width: 32px; height: 32px; @@ -133,7 +133,7 @@ body { } .stop-button { - display: block; + display: none; position: absolute; top: 10px; left: 15px; @@ -148,77 +148,56 @@ body { color: rgba(255, 255, 255, 0.7); } -.truncate { - overflow: hidden; - text-overflow: ellipsis; +/* When the mouse is on the img or the stop-button -> display stop-button */ +li a img:hover + .stop-button { + display: block; } - -.no-padding { - padding: 0px; +li a .stop-button:hover { + display: block; } -.modal-mask { - position: fixed; - z-index: 9998; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-color: rgba(0, 0, 0, .5); - display: table; - transition: opacity .3s ease; +/* transition effect */ +.fade-enter-active { + transition: opacity .3s } - -.modal-wrapper { - display: table-cell; - vertical-align: middle; +.fade-leave-active { + transition: opacity 2.0s } - -.modal-container { - width: 300px; - margin: 0px auto; - padding: 20px 30px; - background-color: #fff; - border-radius: 2px; - box-shadow: 0 2px 8px rgba(0, 0, 0, .33); - transition: all .3s ease; - font-family: Helvetica, Arial, sans-serif; +.fade-enter, .fade-leave-to { + opacity: 0 } -.modal-header h3 { - margin-top: 0; - color: #42b983; +.list-enter, .list-leave-to { + opacity: 0; + transform: translateX(-50px); } - -.modal-body { - margin: 20px 0; +.list-enter-active, .list-leave-active { + transition: all 0.5s; + position: absolute; } - -.modal-default-button { - float: right; +.list-move { + transition: transform .5s; } -/* - * The following styles are auto-applied to elements with - * transition="modal" when their visibility is toggled - * by Vue.js. - * - * You can easily play with the modal transition by editing - * these styles. - */ +.truncate { + overflow: hidden; + text-overflow: ellipsis; +} -.modal-enter { - opacity: 0; +.no-padding { + padding: 0px; } -.modal-leave-active { - opacity: 0; +/* Transition for the modal dialog */ +.modal-fade-enter-active, .modal-fade-leave-active { + transition: opacity .2s +} +.modal-fade-enter, .modal-fade-leave-to { + opacity: 0 } -.modal-enter .modal-container, -.modal-leave-active .modal-container { - -webkit-transform: scale(1.1); - transform: scale(1.1); +.modal-display { + display: block; } .required-field > label::after { diff --git a/remoteappmanager/static/js/admin/vue-components/toolkit/ConfirmDialog.js b/remoteappmanager/static/js/admin/vue-components/toolkit/ConfirmDialog.js index 5145dc177..066e48a47 100644 --- a/remoteappmanager/static/js/admin/vue-components/toolkit/ConfirmDialog.js +++ b/remoteappmanager/static/js/admin/vue-components/toolkit/ConfirmDialog.js @@ -1,7 +1,7 @@ define([ ], function() { "use strict"; - + return { props: { title: { @@ -10,26 +10,26 @@ define([ }, closeCallback: { type: Function, - default: function() {} + default: undefined }, okCallback: { type: Function, default: function() {} } }, - template: '' + - '