Add angular flavors panel
Adding a new panel to the admin dashboard that will use angular js instead of the django templates To test set DISABLED = False in _2081_admin_flavors_panel.py Co-Authored-By: Rajat Vig<rajatv@thoughtworks.com> Co-Authored-By: Errol Pais<epais@thoughtworks.com> Co-Authored-By: Kristine Brown<kbrown@thoughtworks.com> Change-Id: I9394ddfe3791aeb7a52194f37e1e668e33c0325b Partially-Implements: blueprint ng-flavors
This commit is contained in:
parent
e62cdfaadb
commit
65c4895c36
@ -51,8 +51,14 @@
|
||||
*/
|
||||
function gbFilter() {
|
||||
return function (input) {
|
||||
var tb = 1024;
|
||||
|
||||
if (isNaN(input) || null === input) {
|
||||
return '';
|
||||
} else if (input >= tb) {
|
||||
return interpolate(gettext("%s TB"), [parseFloat(Number(input / tb).toFixed(2))]);
|
||||
} else if (input === '') {
|
||||
return interpolate(gettext("0 GB"));
|
||||
} else {
|
||||
return interpolate(gettext("%s GB"), [input.toString()]);
|
||||
}
|
||||
@ -68,8 +74,14 @@
|
||||
*/
|
||||
function mbFilter() {
|
||||
return function (input) {
|
||||
var gb = 1024;
|
||||
|
||||
if (isNaN(input) || null === input) {
|
||||
return '';
|
||||
} else if (input >= gb) {
|
||||
return interpolate(gettext("%s GB"), [parseFloat(Number(input / gb).toFixed(2))]);
|
||||
} else if (input === '') {
|
||||
return interpolate(gettext("0 MB"));
|
||||
} else {
|
||||
return interpolate(gettext("%s MB"), [input.toString()]);
|
||||
}
|
||||
|
@ -47,6 +47,7 @@
|
||||
|
||||
it('returns given numeric value properly', function () {
|
||||
expect(gbFilter(12)).toBe('12 GB');
|
||||
expect(gbFilter(1200)).toBe('1.17 TB');
|
||||
expect(gbFilter(-12)).toBe('-12 GB');
|
||||
expect(gbFilter(12.12)).toBe('12.12 GB');
|
||||
});
|
||||
@ -68,6 +69,7 @@
|
||||
|
||||
it('returns given numeric value properly', function () {
|
||||
expect(mbFilter(12)).toBe('12 MB');
|
||||
expect(mbFilter(1200)).toBe('1.17 GB');
|
||||
expect(mbFilter(-12)).toBe('-12 MB');
|
||||
expect(mbFilter(12.12)).toBe('12.12 MB');
|
||||
});
|
||||
|
24
openstack_dashboard/dashboards/admin/ngflavors/panel.py
Normal file
24
openstack_dashboard/dashboards/admin/ngflavors/panel.py
Normal file
@ -0,0 +1,24 @@
|
||||
# (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.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
import horizon
|
||||
|
||||
|
||||
class NGFlavors(horizon.Panel):
|
||||
name = _("Flavors")
|
||||
slug = 'ngflavors'
|
||||
permissions = ('openstack.services.compute',)
|
@ -0,0 +1,11 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Flavors" %}{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
<hz-page-header header="'{% trans "Flavors" %}'"></hz-page-header>
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<ng-include src="'{{ STATIC_URL }}dashboard/admin/flavors/table/flavors-table.html'"></ng-include>
|
||||
{% endblock %}
|
25
openstack_dashboard/dashboards/admin/ngflavors/urls.py
Normal file
25
openstack_dashboard/dashboards/admin/ngflavors/urls.py
Normal file
@ -0,0 +1,25 @@
|
||||
# (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.
|
||||
|
||||
from django.conf.urls import patterns
|
||||
from django.conf.urls import url
|
||||
|
||||
from openstack_dashboard.dashboards.admin.ngflavors import views
|
||||
|
||||
|
||||
urlpatterns = patterns(
|
||||
'openstack_dashboard.dashboards.admin.ngflavors.views',
|
||||
url(r'^$', views.IndexView.as_view(), name='index'),
|
||||
)
|
19
openstack_dashboard/dashboards/admin/ngflavors/views.py
Normal file
19
openstack_dashboard/dashboards/admin/ngflavors/views.py
Normal file
@ -0,0 +1,19 @@
|
||||
# (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.
|
||||
import horizon.views as views
|
||||
|
||||
|
||||
class IndexView(views.HorizonTemplateView):
|
||||
template_name = 'admin/ngflavors/index.html'
|
@ -25,6 +25,7 @@
|
||||
*/
|
||||
angular
|
||||
.module('horizon.dashboard.admin', [
|
||||
'horizon.dashboard.admin.flavors'
|
||||
])
|
||||
.config(config);
|
||||
|
||||
|
@ -0,0 +1,44 @@
|
||||
/**
|
||||
*
|
||||
* 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(gettext) {
|
||||
return function check(input) {
|
||||
if (input &&
|
||||
angular.isObject(input) &&
|
||||
!angular.isArray(input) &&
|
||||
Object.keys(input).length > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
})();
|
@ -0,0 +1,43 @@
|
||||
/**
|
||||
*
|
||||
* 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(undefined)).not.toBeTruthy();
|
||||
expect(hasExtras({})).not.toBeTruthy();
|
||||
expect(hasExtras('string')).not.toBeTruthy();
|
||||
expect(hasExtras(1)).not.toBeTruthy();
|
||||
expect(hasExtras([1])).not.toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
})();
|
@ -0,0 +1,30 @@
|
||||
/**
|
||||
*
|
||||
* 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', []);
|
||||
|
||||
})();
|
@ -0,0 +1,24 @@
|
||||
/**
|
||||
*
|
||||
* 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();
|
||||
});
|
||||
});
|
||||
|
||||
})();
|
@ -0,0 +1,56 @@
|
||||
/**
|
||||
*
|
||||
* 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 = [];
|
||||
|
||||
init();
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
function init() {
|
||||
nova.getFlavors(true, true).then(onGetFlavors);
|
||||
}
|
||||
|
||||
function onGetFlavors(response) {
|
||||
ctrl.flavors = response.data.items;
|
||||
}
|
||||
|
||||
}
|
||||
})();
|
@ -0,0 +1,67 @@
|
||||
/**
|
||||
*
|
||||
* 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(params) {
|
||||
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 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();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
})();
|
@ -0,0 +1,59 @@
|
||||
<table ng-controller="FlavorsTableController as table"
|
||||
hz-table ng-cloak
|
||||
st-table="table.iflavors"
|
||||
st-safe-src="table.flavors"
|
||||
default-sort="ram"
|
||||
default-sort-reverse="false"
|
||||
class="table-striped table-rsp table-detail modern">
|
||||
|
||||
<thead>
|
||||
|
||||
<tr>
|
||||
<th colspan="100" class="search-header">
|
||||
<hz-search-bar group-classes="input-group-sm" icon-classes="fa-search">
|
||||
</hz-search-bar>
|
||||
</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th class="select-col">
|
||||
<input type="checkbox" hz-select-all="table.iflavors">
|
||||
</th>
|
||||
<th class="rsp-p1" st-sort="name" translate>Flavor Name</th>
|
||||
<th class="rsp-p1" st-sort="vcpus" translate>VCPUs</th>
|
||||
<th class="rsp-p1" st-sort="ram" st-sort-default="ram" translate>RAM</th>
|
||||
<th class="rsp-p2" st-sort="disk" translate>Root Disk</th>
|
||||
<th class="rsp-p2" st-sort="ephermal" translate>Ephemeral Disk</th>
|
||||
<th class="rsp-p2" st-sort="swap" translate>Swap Disk</th>
|
||||
<th class="rsp-p2" st-sort="id" translate>ID</th>
|
||||
<th class="rsp-p2" st-sort="is_public" translate>Public</th>
|
||||
<th class="rsp-p2" st-sort="metadata" translate>Metadata</th>
|
||||
<th class="rsp-p2"></th>
|
||||
</tr>
|
||||
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr ng-repeat="flavor in table.iflavors track by flavor.id">
|
||||
<td class="select-col">
|
||||
<input type="checkbox"
|
||||
ng-model="selected[flavor.id].checked"
|
||||
hz-select="flavor">
|
||||
</td>
|
||||
<td class="rsp-p1">{$ flavor.name $}</td>
|
||||
<td class="rsp-p1">{$ flavor.vcpus $}</td>
|
||||
<td class="rsp-p1">{$ flavor.ram | mb $}</td>
|
||||
<td class="rsp-p2">{$ flavor.disk | gb $}</td>
|
||||
<td class="rsp-p2">{$ flavor.ephemeral | gb $}</td>
|
||||
<td class="rsp-p2">{$ flavor.swap | mb $}</td>
|
||||
<td class="rsp-p2">{$ flavor.id $}</td>
|
||||
<td class="rsp-p2">{$ flavor.is_public | yesno $}</td>
|
||||
<td class="rsp-p2">{$ flavor.extras | hasExtras | yesno $}</td>
|
||||
<td class="rsp-p2">
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<tfoot hz-table-footer items="table.iflavors"></tfoot>
|
||||
|
||||
</table>
|
31
openstack_dashboard/enabled/_2081_admin_flavors_panel.py
Normal file
31
openstack_dashboard/enabled/_2081_admin_flavors_panel.py
Normal file
@ -0,0 +1,31 @@
|
||||
# (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'
|
Loading…
Reference in New Issue
Block a user