From e8e84c2db43043dd9414b823472e4139a0c24e16 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 18 Jul 2016 13:50:00 -0600 Subject: [PATCH] Flavors panel can switch to Angular This patch enables all of the features for the Flavors panel to use Angular but disables it, so that it is easy to switch on/off. Note that we add integration test switches since it can't read the Django conf. Note that I changed the common tests to allow for testing of api calls that don't produce error toasts, because we needed better branch coverage, and the deleteFlavor api wasn't fully branch-tested. Change-Id: I92b1b57bd486e5eb87179cb8d44b7551e9de2e0f Partially-Implements: blueprint ng-flavors --- doc/source/topics/settings.rst | 3 +- .../dashboards/admin/flavors/urls.py | 21 ++- .../dashboards/admin/flavors/views.py | 5 + .../static/dashboard/admin/admin.module.js | 46 ------- .../dashboard/admin/admin.module.spec.js | 38 ------ .../flavors/filters/has-extras.filter.js | 44 ------- .../flavors/filters/has-extras.filter.spec.js | 43 ------- .../dashboard/admin/flavors/flavors.module.js | 30 ----- .../admin/flavors/flavors.module.spec.js | 24 ---- .../flavors/table/flavors-table.controller.js | 87 ------------- .../table/flavors-table.controller.spec.js | 77 ----------- .../admin/flavors/table/flavors-table.html | 63 --------- openstack_dashboard/enabled/_2000_admin.py | 1 - .../enabled/_2080_admin_flavors_panel.py | 15 +++ .../enabled/_2081_admin_flavors_panel.py | 31 ----- ...10_integration_tests_deprecated.py.example | 2 +- openstack_dashboard/settings.py | 1 + .../static/app/core/core.module.js | 1 + .../static/app/core/flavors/flavors.module.js | 121 ++++++++++++++++++ .../app/core/flavors/flavors.service.js | 37 ++++++ .../app/core/flavors/flavors.service.spec.js | 41 ++++++ .../static/app/core/flavors/panel.html | 3 + .../static/app/core/flavors/summary.html | 19 +++ .../openstack-service-api/nova.service.js | 10 +- .../nova.service.spec.js | 11 +- .../test/integration_tests/config.py | 7 + .../test/integration_tests/horizon.conf | 3 + .../pages/admin/system/flavorspage.py | 11 ++ .../integration_tests/tests/test_flavors.py | 30 +++++ openstack_dashboard/test/settings.py | 3 +- .../flavor-panel-switch-6b5cd5f0964f4ba3.yaml | 13 ++ 31 files changed, 333 insertions(+), 508 deletions(-) delete mode 100644 openstack_dashboard/dashboards/admin/static/dashboard/admin/admin.module.js delete mode 100644 openstack_dashboard/dashboards/admin/static/dashboard/admin/admin.module.spec.js delete mode 100644 openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/filters/has-extras.filter.js delete mode 100644 openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/filters/has-extras.filter.spec.js delete mode 100644 openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/flavors.module.js delete mode 100644 openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/flavors.module.spec.js delete mode 100644 openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/table/flavors-table.controller.js delete mode 100644 openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/table/flavors-table.controller.spec.js delete mode 100644 openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/table/flavors-table.html delete mode 100644 openstack_dashboard/enabled/_2081_admin_flavors_panel.py create mode 100644 openstack_dashboard/static/app/core/flavors/flavors.module.js create mode 100644 openstack_dashboard/static/app/core/flavors/flavors.service.js create mode 100644 openstack_dashboard/static/app/core/flavors/flavors.service.spec.js create mode 100644 openstack_dashboard/static/app/core/flavors/panel.html create mode 100644 openstack_dashboard/static/app/core/flavors/summary.html create mode 100644 releasenotes/notes/flavor-panel-switch-6b5cd5f0964f4ba3.yaml diff --git a/doc/source/topics/settings.rst b/doc/source/topics/settings.rst index 64cd3ea19f..e598a30469 100644 --- a/doc/source/topics/settings.rst +++ b/doc/source/topics/settings.rst @@ -432,7 +432,8 @@ This example sorts flavors by vcpus in descending order:: Default:: { - 'images_panel': True + 'images_panel': True, + 'flavors_panel': False, } A dictionary of currently available AngularJS features. This allows simple diff --git a/openstack_dashboard/dashboards/admin/flavors/urls.py b/openstack_dashboard/dashboards/admin/flavors/urls.py index 4f044b483c..6739aa50a2 100644 --- a/openstack_dashboard/dashboards/admin/flavors/urls.py +++ b/openstack_dashboard/dashboards/admin/flavors/urls.py @@ -16,13 +16,24 @@ # License for the specific language governing permissions and limitations # under the License. +from django.conf import settings from django.conf.urls import url from openstack_dashboard.dashboards.admin.flavors import views -urlpatterns = [ - url(r'^$', views.IndexView.as_view(), name='index'), - url(r'^create/$', views.CreateView.as_view(), name='create'), - url(r'^(?P[^/]+)/update/$', views.UpdateView.as_view(), name='update'), -] +if settings.ANGULAR_FEATURES['flavors_panel']: + # New angular panel + urlpatterns = [ + url(r'^$', views.AngularIndexView.as_view(), name='index'), + url(r'^create/$', views.AngularIndexView.as_view(), name='create'), + url(r'^(?P[^/]+)/update/$', views.AngularIndexView.as_view(), + name='index'), + ] +else: + urlpatterns = [ + url(r'^$', views.IndexView.as_view(), name='index'), + url(r'^create/$', views.CreateView.as_view(), name='create'), + url(r'^(?P[^/]+)/update/$', + views.UpdateView.as_view(), name='update'), + ] diff --git a/openstack_dashboard/dashboards/admin/flavors/views.py b/openstack_dashboard/dashboards/admin/flavors/views.py index 0bfc44ed5c..a4322ce307 100644 --- a/openstack_dashboard/dashboards/admin/flavors/views.py +++ b/openstack_dashboard/dashboards/admin/flavors/views.py @@ -18,6 +18,7 @@ from django.core.urlresolvers import reverse_lazy from django.utils.translation import ugettext_lazy as _ +from django.views import generic from horizon import exceptions from horizon import tables @@ -34,6 +35,10 @@ from openstack_dashboard.dashboards.admin.flavors \ INDEX_URL = "horizon:admin:flavors:index" +class AngularIndexView(generic.TemplateView): + template_name = 'angular.html' + + class IndexView(tables.DataTableView): table_class = project_tables.FlavorsTable template_name = 'admin/flavors/index.html' diff --git a/openstack_dashboard/dashboards/admin/static/dashboard/admin/admin.module.js b/openstack_dashboard/dashboards/admin/static/dashboard/admin/admin.module.js deleted file mode 100644 index b068dca036..0000000000 --- a/openstack_dashboard/dashboards/admin/static/dashboard/admin/admin.module.js +++ /dev/null @@ -1,46 +0,0 @@ -/** - * - * Licensed 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. - */ - -(function() { - 'use strict'; - - /** - * @ngdoc horizon.dashboard.admin - * @ngModule - * - * @description - * Dashboard module to host various admin panels. - */ - angular - .module('horizon.dashboard.admin', [ - 'horizon.dashboard.admin.flavors' - ]) - .config(config); - - config.$inject = [ - '$provide', - '$windowProvider' - ]; - - /** - * @name horizon.dashboard.admin.basePath - * @description Base path for the admin dashboard - */ - function config($provide, $windowProvider) { - var path = $windowProvider.$get().STATIC_URL + 'dashboard/admin/'; - $provide.constant('horizon.dashboard.admin.basePath', path); - } - -})(); diff --git a/openstack_dashboard/dashboards/admin/static/dashboard/admin/admin.module.spec.js b/openstack_dashboard/dashboards/admin/static/dashboard/admin/admin.module.spec.js deleted file mode 100644 index d9ca3f6df4..0000000000 --- a/openstack_dashboard/dashboards/admin/static/dashboard/admin/admin.module.spec.js +++ /dev/null @@ -1,38 +0,0 @@ -/** - * - * Licensed 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. - */ -(function() { - 'use strict'; - - describe('horizon.dashboard.admin', function() { - var staticUrl, basePath; - - beforeEach(module('horizon.dashboard.admin')); - - beforeEach(inject(function($injector) { - staticUrl = $injector.get('$window').STATIC_URL; - basePath = $injector.get('horizon.dashboard.admin.basePath'); - })); - - it('should exist', function() { - expect(angular.module('horizon.dashboard.admin')).toBeDefined(); - }); - - it('should set path properly', function () { - expect(basePath).toEqual(staticUrl + 'dashboard/admin/'); - }); - - }); - -})(); diff --git a/openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/filters/has-extras.filter.js b/openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/filters/has-extras.filter.js deleted file mode 100644 index 80017bb6e6..0000000000 --- a/openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/filters/has-extras.filter.js +++ /dev/null @@ -1,44 +0,0 @@ -/** - * - * Licensed 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. - */ -(function () { - 'use strict'; - - angular - .module('horizon.dashboard.admin.flavors') - .filter('hasExtras', hasExtrasFilter); - - hasExtrasFilter.$inject = []; - - /** - * @ngdoc filter - * @name hasExtrasFilter - * @description - * If input is defined and has more than one property return 'Yes' else return 'No' - * - */ - function hasExtrasFilter() { - return function check(input) { - if (input && - angular.isObject(input) && - !angular.isArray(input) && - Object.keys(input).length > 0) { - return true; - } - - return false; - }; - } - -})(); diff --git a/openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/filters/has-extras.filter.spec.js b/openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/filters/has-extras.filter.spec.js deleted file mode 100644 index 6c53f4125e..0000000000 --- a/openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/filters/has-extras.filter.spec.js +++ /dev/null @@ -1,43 +0,0 @@ -/** - * - * Licensed 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. - */ -(function() { - 'use strict'; - - describe('horizon.dashboard.admin.flavors.hasExtras', function() { - - var hasExtras; - - beforeEach(module('horizon.framework.util.i18n')); - beforeEach(module('horizon.dashboard.admin.flavors')); - - beforeEach(inject(function(_hasExtrasFilter_) { - hasExtras = _hasExtrasFilter_; - })); - - it('returns Yes when key is present', function() { - var input = { 1: 'test' }; - expect(hasExtras(input)).toBeTruthy(); - }); - - it('returns No when object is undefined or has no properties', function() { - expect(hasExtras()).not.toBeTruthy(); - expect(hasExtras({})).not.toBeTruthy(); - expect(hasExtras('string')).not.toBeTruthy(); - expect(hasExtras(1)).not.toBeTruthy(); - expect(hasExtras([1])).not.toBeTruthy(); - }); - }); - -})(); diff --git a/openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/flavors.module.js b/openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/flavors.module.js deleted file mode 100644 index 2f1f106745..0000000000 --- a/openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/flavors.module.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * - * Licensed 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. - */ - -(function() { - 'use strict'; - - /** - * @ngdoc horizon.dashboard.admin.flavors - * @ngModule - * - * @description - * Provides all of the services and widgets required - * to support and display the flavors panel. - */ - angular - .module('horizon.dashboard.admin.flavors', []); - -})(); diff --git a/openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/flavors.module.spec.js b/openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/flavors.module.spec.js deleted file mode 100644 index 5a35e76c5f..0000000000 --- a/openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/flavors.module.spec.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * - * Licensed 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. - */ -(function () { - 'use strict'; - - describe('horizon.dashboard.admin.flavors', function () { - it('should exist', function () { - expect(angular.module('horizon.dashboard.admin.flavors')).toBeDefined(); - }); - }); - -})(); diff --git a/openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/table/flavors-table.controller.js b/openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/table/flavors-table.controller.js deleted file mode 100644 index b5b7d3f4da..0000000000 --- a/openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/table/flavors-table.controller.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * - * Licensed 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. - */ - -(function() { - 'use strict'; - - angular - .module('horizon.dashboard.admin.flavors') - .controller('FlavorsTableController', FlavorsTableController); - - FlavorsTableController.$inject = [ - 'horizon.app.core.openstack-service-api.nova' - ]; - - /** - * @ngdoc FlavorsTableController - * @ngController - * - * @description - * Controller for the flavors panel. - * Serves as the focal point for table actions. - */ - function FlavorsTableController( - nova - ) { - var ctrl = this; - - ctrl.flavors = []; - ctrl.iflavors = []; - - ctrl.searchFacets = getSearchFacets(); - - init(); - - //////////////////////////////// - - function init() { - nova.getFlavors(true, true).then(onGetFlavors); - } - - function onGetFlavors(response) { - ctrl.flavors = response.data.items; - } - - function getSearchFacets() { - return [ - { - label: gettext('Name'), - name: 'name', - singleton: true - }, - { - label: gettext('VCPUs'), - name: 'vcpus', - singleton: true - }, - { - label: gettext('RAM'), - name: 'ram', - singleton: true - }, - { - label: gettext('Public'), - name: 'os-flavor-access:is_public', - singleton: true, - options: [ - {label: gettext('Yes'), key: 'true'}, - {label: gettext('No'), key: 'false'} - ] - } - ]; - } - - } -})(); diff --git a/openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/table/flavors-table.controller.spec.js b/openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/table/flavors-table.controller.spec.js deleted file mode 100644 index ab7ceabd60..0000000000 --- a/openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/table/flavors-table.controller.spec.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * - * Licensed 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. - */ -(function () { - 'use strict'; - - describe('horizon.dashboard.admin.flavors.controller.FlavorsTableController', function () { - - var flavors = [{id: '1'}, {id: '2'}]; - - var novaAPI = { - getFlavors: function() { - var deferred = $q.defer(); - deferred.resolve({data: {items: flavors}}); - return deferred.promise; - } - }; - - var controller, $q, $scope; - - beforeEach(module('horizon.framework')); - - beforeEach(module('horizon.app.core.openstack-service-api', function($provide) { - $provide.value('horizon.app.core.openstack-service-api.nova', novaAPI); - })); - - beforeEach(module('horizon.dashboard.admin', function($provide) { - $provide.constant('horizon.dashboard.admin.basePath', '/a/sample/path/'); - })); - - beforeEach(module('horizon.dashboard.admin.flavors')); - - beforeEach(inject(function ($injector, _$rootScope_) { - $scope = _$rootScope_.$new(); - $q = $injector.get('$q'); - controller = $injector.get('$controller'); - })); - - function createController() { - return controller('FlavorsTableController', {}); - } - - it('should set facets for search', function () { - var ctrl = createController(); - expect(ctrl.searchFacets).toBeDefined(); - expect(ctrl.searchFacets.length).toEqual(4); - expect(ctrl.searchFacets[0].name).toEqual('name'); - expect(ctrl.searchFacets[1].name).toEqual('vcpus'); - expect(ctrl.searchFacets[2].name).toEqual('ram'); - expect(ctrl.searchFacets[3].name).toEqual('os-flavor-access:is_public'); - }); - - it('should invoke nova apis', function() { - spyOn(novaAPI, 'getFlavors').and.callThrough(); - - var ctrl = createController(); - $scope.$apply(); - - expect(novaAPI.getFlavors).toHaveBeenCalled(); - expect(ctrl.flavors).toEqual(flavors); - expect(ctrl.iflavors).toBeDefined(); - }); - - }); - -})(); diff --git a/openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/table/flavors-table.html b/openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/table/flavors-table.html deleted file mode 100644 index b6a578e7b5..0000000000 --- a/openstack_dashboard/dashboards/admin/static/dashboard/admin/flavors/table/flavors-table.html +++ /dev/null @@ -1,63 +0,0 @@ -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - Flavor NameVCPUsRAMRoot DiskEphemeral DiskSwap DiskRX/TX factorIDPublicMetadata
- - {$ flavor.name $}{$ flavor.vcpus $}{$ flavor.ram | mb $}{$ flavor.disk | gb $}{$ flavor.ephemeral | gb $}{$ flavor.swap | mb $}{$ flavor.rxtx_factor $}{$ flavor.id $}{$ flavor.is_public | yesno $}{$ flavor.extras | hasExtras | yesno $} -
-
-
diff --git a/openstack_dashboard/enabled/_2000_admin.py b/openstack_dashboard/enabled/_2000_admin.py index 34363d770a..50972cd547 100644 --- a/openstack_dashboard/enabled/_2000_admin.py +++ b/openstack_dashboard/enabled/_2000_admin.py @@ -21,7 +21,6 @@ ADD_INSTALLED_APPS = [ ] ADD_ANGULAR_MODULES = [ - 'horizon.dashboard.admin', ] AUTO_DISCOVER_STATIC_FILES = True diff --git a/openstack_dashboard/enabled/_2080_admin_flavors_panel.py b/openstack_dashboard/enabled/_2080_admin_flavors_panel.py index ee4001895a..9e4109767f 100644 --- a/openstack_dashboard/enabled/_2080_admin_flavors_panel.py +++ b/openstack_dashboard/enabled/_2080_admin_flavors_panel.py @@ -1,3 +1,18 @@ +# (c) Copyright 2016 Hewlett Packard Enterprise Development LP +# +# Licensed 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. + # The slug of the panel to be added to HORIZON_CONFIG. Required. PANEL = 'flavors' # The slug of the dashboard the PANEL associated with. Required. diff --git a/openstack_dashboard/enabled/_2081_admin_flavors_panel.py b/openstack_dashboard/enabled/_2081_admin_flavors_panel.py deleted file mode 100644 index 7efcbd2066..0000000000 --- a/openstack_dashboard/enabled/_2081_admin_flavors_panel.py +++ /dev/null @@ -1,31 +0,0 @@ -# (c) Copyright 2015 Hewlett-Packard Development Company, L.P. -# (c) Copyright 2015 ThoughtWorks, Inc. -# -# Licensed 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. - -# The slug of the dashboard the PANEL associated with. Required. -PANEL_DASHBOARD = 'admin' - -# The slug of the panel group the PANEL is associated with. -# If you want the panel to show up without a panel group, -# use the panel group "default". -PANEL_GROUP = 'admin' - -# The slug of the panel to be added to HORIZON_CONFIG. Required. -PANEL = 'ngflavors' - -# If set to True, this settings file will not be added to the settings. -DISABLED = True - -# Python panel class of the PANEL to be added. -ADD_PANEL = 'openstack_dashboard.dashboards.admin.ngflavors.panel.NGFlavors' diff --git a/openstack_dashboard/local/local_settings.d/_2010_integration_tests_deprecated.py.example b/openstack_dashboard/local/local_settings.d/_2010_integration_tests_deprecated.py.example index 87c9e6718b..2028a2c7d9 100644 --- a/openstack_dashboard/local/local_settings.d/_2010_integration_tests_deprecated.py.example +++ b/openstack_dashboard/local/local_settings.d/_2010_integration_tests_deprecated.py.example @@ -2,4 +2,4 @@ # wanting to only test legacy panels. Since 'local' modules are evaluated # after settings.py, these configurations will override the default settings. -ANGULAR_FEATURES.update({"images_panel": False}) \ No newline at end of file +ANGULAR_FEATURES.update({"images_panel": False, "flavors_panel": False}) diff --git a/openstack_dashboard/settings.py b/openstack_dashboard/settings.py index 7a9c5a83b8..3ec6992f81 100644 --- a/openstack_dashboard/settings.py +++ b/openstack_dashboard/settings.py @@ -305,6 +305,7 @@ COMPRESS_OFFLINE_CONTEXT = 'horizon.themes.offline_context' # Dictionary of currently available angular features ANGULAR_FEATURES = { 'images_panel': True, + 'flavors_panel': False, } # Notice all customizable configurations should be above this line diff --git a/openstack_dashboard/static/app/core/core.module.js b/openstack_dashboard/static/app/core/core.module.js index 8ecfc58ff8..eebfb5c317 100644 --- a/openstack_dashboard/static/app/core/core.module.js +++ b/openstack_dashboard/static/app/core/core.module.js @@ -33,6 +33,7 @@ .module('horizon.app.core', [ 'horizon.app.core.conf', 'horizon.app.core.cloud-services', + 'horizon.app.core.flavors', 'horizon.app.core.images', 'horizon.app.core.metadata', 'horizon.app.core.openstack-service-api', diff --git a/openstack_dashboard/static/app/core/flavors/flavors.module.js b/openstack_dashboard/static/app/core/flavors/flavors.module.js new file mode 100644 index 0000000000..5f9b23daf7 --- /dev/null +++ b/openstack_dashboard/static/app/core/flavors/flavors.module.js @@ -0,0 +1,121 @@ +/** + * (c) Copyright 2015 Hewlett-Packard Development Company, L.P. + * + * Licensed 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. + */ + +(function() { + 'use strict'; + + /** + * @ngdoc overview + * @ngname horizon.app.core.flavors + * + * @description + * Provides all of the services and widgets required + * to support and display flavors related content. + */ + angular + .module('horizon.app.core.flavors', [ + 'ngRoute', + 'horizon.framework.conf', + 'horizon.app.core' + ]) + .constant('horizon.app.core.flavors.resourceType', 'OS::Nova::Flavor') + .run(run) + .config(config); + + run.$inject = [ + 'horizon.framework.conf.resource-type-registry.service', + 'horizon.app.core.flavors.basePath', + 'horizon.app.core.flavors.service', + 'horizon.app.core.flavors.resourceType' + ]; + + function run(registry, basePath, flavorsService, flavorResourceType) { + registry.getResourceType(flavorResourceType) + .setNames(gettext('Flavor'), gettext('Flavors')) + .setSummaryTemplateUrl(basePath + 'summary.html') + .setProperties(flavorProperties()) + .setListFunction(flavorsService.getFlavorsPromise) + .tableColumns + .append({ + id: 'name', + priority: 1 + }) + .append({ + id: 'vcpus', + priority: 2 + }) + .append({ + id: 'ram', + priority: 1, + sortDefault: true + }) + .append({ + id: 'disk', + priority: 2 + }) + .append({ + id: 'id', + priority: 1 + }) + .append({ + id: 'os-flavor-access:is_public', + priority: 2 + }); + + /** + * @name roleProperties + * @description resource properties for flavor module + */ + function flavorProperties() { + return { + name: gettext('Flavor Name'), + vcpus: gettext('VCPUs'), + ram: {label: gettext('RAM'), filters: ['mb']}, + disk: {label: gettext('Root Disk'), filters: ['gb']}, + 'OS-FLV-EXT-DATA:ephemeral': {label: gettext('Ephmeral Disk'), filters: ['gb']}, + swap: {label: gettext('Swap Disk'), filters: ['gb']}, + rxtx_factor: gettext('RX/TX Factor'), + id: gettext('ID'), + 'os-flavor-access:is_public': {label: gettext('Public'), filters: ['yesno']}, + metadata: gettext('Metadata') + }; + } + } + + config.$inject = [ + '$provide', + '$windowProvider', + '$routeProvider' + ]; + + /** + * @name config + * @param {Object} $provide + * @param {Object} $windowProvider + * @param {Object} $routeProvider + * @description Routes used by this module. + * @returns {undefined} Returns nothing + */ + function config($provide, $windowProvider, $routeProvider) { + var path = $windowProvider.$get().STATIC_URL + 'app/core/flavors/'; + $provide.constant('horizon.app.core.flavors.basePath', path); + + $routeProvider.when('/admin/flavors', { + templateUrl: path + 'panel.html' + }); + } + +})(); diff --git a/openstack_dashboard/static/app/core/flavors/flavors.service.js b/openstack_dashboard/static/app/core/flavors/flavors.service.js new file mode 100644 index 0000000000..fdb960ae4a --- /dev/null +++ b/openstack_dashboard/static/app/core/flavors/flavors.service.js @@ -0,0 +1,37 @@ +/* + * (c) Copyright 2016 Hewlett Packard Enterprise Development LP + * + * Licensed 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. + */ +(function() { + "use strict"; + + angular.module('horizon.app.core.flavors') + .factory('horizon.app.core.flavors.service', flavorsService); + + flavorsService.$inject = [ + 'horizon.app.core.openstack-service-api.nova' + ]; + + function flavorsService(nova) { + return { + getFlavorsPromise: getFlavorsPromise + }; + + function getFlavorsPromise(params) { + var fullParams = angular.extend({}, params, {get_extras: true}); + return nova.getFlavors(fullParams); + } + } + +})(); diff --git a/openstack_dashboard/static/app/core/flavors/flavors.service.spec.js b/openstack_dashboard/static/app/core/flavors/flavors.service.spec.js new file mode 100644 index 0000000000..76bb25aa2d --- /dev/null +++ b/openstack_dashboard/static/app/core/flavors/flavors.service.spec.js @@ -0,0 +1,41 @@ +/* + * (c) Copyright 2016 Hewlett Packard Enterprise Development LP + * + * Licensed 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. + */ + +(function() { + "use strict"; + + describe('flavors service', function() { + var service; + beforeEach(module('horizon.framework.util')); + beforeEach(module('horizon.framework.conf')); + beforeEach(module('horizon.app.core.flavors')); + beforeEach(inject(function($injector) { + service = $injector.get('horizon.app.core.flavors.service'); + })); + + describe('getFlavorsPromise', function() { + it("provides a promise that gets translated", inject(function($q, $injector) { + var glance = $injector.get('horizon.app.core.openstack-service-api.nova'); + var deferred = $q.defer(); + spyOn(glance, 'getFlavors').and.returnValue(deferred.promise); + service.getFlavorsPromise({}); + deferred.resolve({data: {items: [{id: 1, updated_at: 'jul1'}]}}); + expect(glance.getFlavors).toHaveBeenCalled(); + })); + }); + + }); +})(); diff --git a/openstack_dashboard/static/app/core/flavors/panel.html b/openstack_dashboard/static/app/core/flavors/panel.html new file mode 100644 index 0000000000..4e30c10c38 --- /dev/null +++ b/openstack_dashboard/static/app/core/flavors/panel.html @@ -0,0 +1,3 @@ + + + diff --git a/openstack_dashboard/static/app/core/flavors/summary.html b/openstack_dashboard/static/app/core/flavors/summary.html new file mode 100644 index 0000000000..01b2a51968 --- /dev/null +++ b/openstack_dashboard/static/app/core/flavors/summary.html @@ -0,0 +1,19 @@ + + +
+
+
+
+
{$ key $}
+
{$ value $}
+
+
+
+
diff --git a/openstack_dashboard/static/app/core/openstack-service-api/nova.service.js b/openstack_dashboard/static/app/core/openstack-service-api/nova.service.js index 30a66e49f3..cd06208afa 100644 --- a/openstack_dashboard/static/app/core/openstack-service-api/nova.service.js +++ b/openstack_dashboard/static/app/core/openstack-service-api/nova.service.js @@ -468,14 +468,8 @@ * call per flavor). * @returns {Object} The result of the API call */ - function getFlavors(isPublic, getExtras) { - var config = {'params': {}}; - if (isPublic) { - config.params.is_public = 'true'; - } - if (getExtras) { - config.params.get_extras = 'true'; - } + function getFlavors(params) { + var config = params ? { 'params' : params} : { 'params' : {} }; return apiService.get('/api/nova/flavors/', config) .success(function (data) { // The colon character ':' in the flavor data causes problems when used diff --git a/openstack_dashboard/static/app/core/openstack-service-api/nova.service.spec.js b/openstack_dashboard/static/app/core/openstack-service-api/nova.service.spec.js index 967d2f7855..bd92338e5a 100644 --- a/openstack_dashboard/static/app/core/openstack-service-api/nova.service.spec.js +++ b/openstack_dashboard/static/app/core/openstack-service-api/nova.service.spec.js @@ -286,8 +286,6 @@ }, "error": "Unable to retrieve the flavors.", "testInput": [ - false, - false ] }, { @@ -301,8 +299,7 @@ }, "error": "Unable to retrieve the flavors.", "testInput": [ - true, - false + {is_public: "true"} ] }, { @@ -316,8 +313,7 @@ }, "error": "Unable to retrieve the flavors.", "testInput": [ - false, - true + {get_extras: "true"} ] }, { @@ -332,8 +328,7 @@ }, "error": "Unable to retrieve the flavors.", "testInput": [ - true, - true + {is_public: "true", get_extras: "true"} ] }, { diff --git a/openstack_dashboard/test/integration_tests/config.py b/openstack_dashboard/test/integration_tests/config.py index 2bcb6abb4d..668bc1d321 100644 --- a/openstack_dashboard/test/integration_tests/config.py +++ b/openstack_dashboard/test/integration_tests/config.py @@ -102,6 +102,12 @@ SeleniumGroup = [ help="Is the browser size maximized for each test?"), ] +FlavorsGroup = [ + cfg.StrOpt('panel_type', + default='legacy', + help='type/version of flavors panel'), +] + ScenarioGroup = [ cfg.StrOpt('ssh_user', default='cirros', @@ -163,6 +169,7 @@ def get_config(): cfg.CONF.register_opts(NetworkGroup, group="network") cfg.CONF.register_opts(AvailableServiceGroup, group="service_available") cfg.CONF.register_opts(SeleniumGroup, group="selenium") + cfg.CONF.register_opts(FlavorsGroup, group="flavors") cfg.CONF.register_opts(ImageGroup, group="image") cfg.CONF.register_opts(ScenarioGroup, group="scenario") cfg.CONF.register_opts(InstancesGroup, group="launch_instances") diff --git a/openstack_dashboard/test/integration_tests/horizon.conf b/openstack_dashboard/test/integration_tests/horizon.conf index a4eeba0080..a83249956a 100644 --- a/openstack_dashboard/test/integration_tests/horizon.conf +++ b/openstack_dashboard/test/integration_tests/horizon.conf @@ -33,6 +33,9 @@ explicit_wait=90 # (boolean) maximize_browser=yes +[flavors] +panel_type=legacy + [image] # http accessible image (string value) panel_type=angular diff --git a/openstack_dashboard/test/integration_tests/pages/admin/system/flavorspage.py b/openstack_dashboard/test/integration_tests/pages/admin/system/flavorspage.py index b28780e694..70da247248 100644 --- a/openstack_dashboard/test/integration_tests/pages/admin/system/flavorspage.py +++ b/openstack_dashboard/test/integration_tests/pages/admin/system/flavorspage.py @@ -15,6 +15,8 @@ from openstack_dashboard.test.integration_tests.regions import forms from openstack_dashboard.test.integration_tests.regions import menus from openstack_dashboard.test.integration_tests.regions import tables +from selenium.webdriver.common import by + class FlavorsTable(tables.TableRegion): name = "flavors" @@ -144,3 +146,12 @@ class FlavorsPage(basepage.BaseNavigationPage): def is_flavor_public(self, name): row = self._get_flavor_row(name) return row.cells[self.FLAVORS_TABLE_PUBLIC_COLUMN].text == "Yes" + + +class FlavorsPageNG(FlavorsPage): + _resource_page_header_locator = (by.By.CSS_SELECTOR, + 'hz-resource-panel hz-page-header h1') + + @property + def header(self): + return self._get_element(*self._resource_page_header_locator) diff --git a/openstack_dashboard/test/integration_tests/tests/test_flavors.py b/openstack_dashboard/test/integration_tests/tests/test_flavors.py index 5e0400b720..f427b0ccf8 100644 --- a/openstack_dashboard/test/integration_tests/tests/test_flavors.py +++ b/openstack_dashboard/test/integration_tests/tests/test_flavors.py @@ -12,10 +12,28 @@ import random +from openstack_dashboard.test.integration_tests import decorators from openstack_dashboard.test.integration_tests import helpers from openstack_dashboard.test.integration_tests.regions import messages +@decorators.config_option_required('flavors.panel_type', 'angular', + message="Legacy Panels not tested") +class TestFlavorAngular(helpers.AdminTestCase): + @property + def flavors_page(self): + from openstack_dashboard.test.integration_tests.pages.admin.\ + system.flavorspage import FlavorsPageNG + self.home_pg.go_to_system_flavorspage() + return FlavorsPageNG(self.driver, self.CONFIG) + + def test_basic_flavors_browse(self): + flavors_page = self.flavors_page + self.assertEqual(flavors_page.header.text, 'Flavors') + + +@decorators.config_option_required('flavors.panel_type', 'legacy', + message="Angular Panels not tested") class TestFlavors(helpers.AdminTestCase): FLAVOR_NAME = helpers.gen_random_resource_name("flavor") @@ -48,6 +66,18 @@ class TestFlavors(helpers.AdminTestCase): self.assertFalse( self.flavors_page.is_flavor_present(self.FLAVOR_NAME)) + def test_flavor_header(self): + header_text = self.driver.find_element_by_tag_name('h1').text + self.assertEqual(header_text, 'Flavors') + + def test_flavor_module_exists(self): + js_cmd = "$('html').append('
'"\ + " + angular.module('horizon.app.core.flavors').name"\ + " + '
');" + self.driver.execute_script(js_cmd) + value = self.driver.find_element_by_id('testonly').text + self.assertEqual(value, 'horizon.app.core.flavors') + def test_flavor_create(self): """tests the flavor creation and deletion functionalities: * creates a new flavor diff --git a/openstack_dashboard/test/settings.py b/openstack_dashboard/test/settings.py index 4aab9cf9f4..9b593061af 100644 --- a/openstack_dashboard/test/settings.py +++ b/openstack_dashboard/test/settings.py @@ -99,7 +99,8 @@ HORIZON_CONFIG = { } ANGULAR_FEATURES = { - 'images_panel': False # Use the legacy panel so unit tests are still run + 'images_panel': False, # Use the legacy panel so unit tests are still run + 'flavors_panel': False, } STATICFILES_DIRS = settings_utils.get_xstatic_dirs( diff --git a/releasenotes/notes/flavor-panel-switch-6b5cd5f0964f4ba3.yaml b/releasenotes/notes/flavor-panel-switch-6b5cd5f0964f4ba3.yaml new file mode 100644 index 0000000000..2c3812bc74 --- /dev/null +++ b/releasenotes/notes/flavor-panel-switch-6b5cd5f0964f4ba3.yaml @@ -0,0 +1,13 @@ +--- +prelude: > + The Flavor panel now may be configured to use + either the legacy or Angular code. +features: + - ANGULAR_FEATURES now allows for a key 'flavors_panel' to be + specified as True or False indicating whether the Angular + version of the panel is enabled. + - Integration tests for Flavor features may also be toggled + in openstack_dashboard/test/integration_tests/horizon.conf + using the 'panel_type' feature in the 'flavors' setting, + either set to 'legacy' or 'angular' to match the enabled + panel type.