Add quotas panel for admin

This patch adds quotas table view for admin user.

To enable quotas panel, copy followings into horizon's
openstack_dashboard/local/enabled directory.

magnum_ui/enabled/_2370_admin_container_infra_panel_group.py
magnum_ui/enabled/_2371_admin_container_infra_quotas_panel.py

Change-Id: I2ae154ef15f537451c46ec46cab1ee9cb3ceef6c
Partial-Implements: blueprint add-quotas-panel
This commit is contained in:
Shu Muto 2017-12-15 15:50:33 +09:00 committed by Shu Muto
parent d78285db9d
commit dd70cba6dd
13 changed files with 363 additions and 2 deletions

View File

@ -254,7 +254,7 @@ class Quotas(generic.View):
item under this is a Quota.
"""
result = magnum.quotas_list(request)
return {'items': [change_to_id(n.to_dict()) for n in result]}
return {'items': [n.to_dict() for n in result]}
@rest_utils.ajax(data_required=True)
def post(self, request):
@ -264,7 +264,7 @@ class Quotas(generic.View):
"""
created = magnum.quotas_create(request, **request.DATA)
return rest_utils.CreatedResponse(
('/api/container_infra/quotas/%s/%s' % created.uuid,
('/api/container_infra/quotas/%s/%s' % created.id,
created.resource),
created.to_dict())

View File

@ -0,0 +1,20 @@
# 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 Quotas(horizon.Panel):
name = _("Quotas")
slug = "container_infra.quotas"

View File

@ -0,0 +1,26 @@
# 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 url
from django.utils.translation import ugettext_lazy as _
from horizon.browsers import views
from magnum_ui.content.container_infra.quotas import panel
title = _("Container Infra - Quotas")
page_title = panel.Quotas.name
urlpatterns = [
url(r'^$',
views.AngularIndexView.as_view(title=title, page_title=page_title),
name='index'),
]

View File

@ -0,0 +1,19 @@
# 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 _
# The slug of the panel group to be added to HORIZON_CONFIG. Required.
PANEL_GROUP = 'container_infra'
# The display name of the PANEL_GROUP. Required.
PANEL_GROUP_NAME = _('Container Infra')
# The slug of the dashboard the PANEL_GROUP associated with. Required.
PANEL_GROUP_DASHBOARD = 'admin'

View File

@ -0,0 +1,21 @@
# 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 = 'container_infra.quotas'
# The slug of the panel group the PANEL is associated with.
PANEL_GROUP = 'container_infra'
# The slug of the dashboard the PANEL associated with. Required.
PANEL_DASHBOARD = 'admin'
# Python panel class of the PANEL to be added.
ADD_PANEL = 'magnum_ui.content.container_infra.quotas.panel.Quotas'

View File

@ -28,6 +28,7 @@
.module('horizon.dashboard.container-infra', [
'horizon.dashboard.container-infra.clusters',
'horizon.dashboard.container-infra.cluster-templates',
'horizon.dashboard.container-infra.quotas',
'ngRoute'
])
.config(config);

View File

@ -0,0 +1,4 @@
<hz-resource-panel resource-type-name="OS::Magnum::Quota">
<hz-resource-table resource-type-name="OS::Magnum::Quota"
track-by="trackBy"></hz-resource-table>
</hz-resource-panel>

View File

@ -0,0 +1,149 @@
/**
* 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
* @name horizon.dashboard.container-infra.quotas
* @ngModule
* @description
* Provides all the services and widgets require to display the quotas template
* panel
*/
angular
.module('horizon.dashboard.container-infra.quotas',
[
'ngRoute'
])
.constant('horizon.dashboard.container-infra.quotas.events', events())
.constant(
'horizon.dashboard.container-infra.quotas.resourceType',
'OS::Magnum::Quota')
.run(run)
.config(config);
/**
* @ngdoc constant
* @name events
* @returns {Object} The event object
* @description A list of events for quotas
*/
function events() {
return {
CREATE_SUCCESS: 'horizon.dashboard.container-infra.quotas.CREATE_SUCCESS',
UPDATE_SUCCESS: 'horizon.dashboard.container-infra.quotas.UPDATE_SUCCESS',
DELETE_SUCCESS: 'horizon.dashboard.container-infra.quotas.DELETE_SUCCESS'
};
}
run.$inject = [
'horizon.framework.conf.resource-type-registry.service',
'horizon.dashboard.container-infra.quotas.service',
'horizon.dashboard.container-infra.quotas.basePath',
'horizon.dashboard.container-infra.quotas.resourceType'
];
function run(registry, quotasService, basePath, resourceType) {
registry.getResourceType(resourceType)
.setNames(gettext('Quota'), gettext('Quotas'))
// for table row items.
.setProperty('id', {
label: gettext('ID')
})
.setProperty('project_id', {
label: gettext('Project ID')
})
.setProperty('resource', {
label: gettext('Resource')
})
.setProperty('hard_limit', {
label: gettext('Hard Limit')
})
.setProperty('created_at', {
label: gettext('Created At')
})
.setProperty('updated_at', {
label: gettext('Updated At')
})
.setListFunction(quotasService.getQuotasPromise)
.tableColumns
.append({
id: 'id',
priority: 1
})
.append({
id: 'project_id',
priority: 1
})
.append({
id: 'resource',
priority: 1
})
.append({
id: 'hard_limit',
priority: 1
})
.append({
id: 'created_at',
priority: 2,
filters: ['simpleDate']
})
.append({
id: 'updated_at',
priority: 2,
filters: ['simpleDate']
});
// for magic-search
registry.getResourceType(resourceType).filterFacets
.append({
'label': gettext('Project ID'),
'name': 'project_id',
'singleton': true
})
.append({
'label': gettext('Resource'),
'name': 'resource',
'singleton': true
})
.append({
'label': gettext('Hard Limit'),
'name': 'hard_limit',
'singleton': true
});
}
config.$inject = [
'$provide',
'$windowProvider',
'$routeProvider'
];
/**
* @name config
* @param {Object} $provide
* @param {Object} $windowProvider
* @param {Object} $routeProvider
* @returns {undefined} Returns nothing
* @description Routes used by this module.
*/
function config($provide, $windowProvider, $routeProvider) {
var path = $windowProvider.$get().STATIC_URL + 'dashboard/container-infra/quotas/';
$provide.constant('horizon.dashboard.container-infra.quotas.basePath', path);
$routeProvider.when('/admin/container_infra/quotas', {
templateUrl: path + 'panel.html'
});
}
})();

View File

@ -0,0 +1,23 @@
/**
* 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.container-infra.quotas', function() {
it('should exist', function() {
expect(angular.module('horizon.dashboard.container-infra.quotas')).toBeDefined();
});
});
})();

View File

@ -0,0 +1,55 @@
/**
* 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.container-infra.quotas')
.factory('horizon.dashboard.container-infra.quotas.service',
quotasService);
quotasService.$inject = [
'$filter',
'horizon.app.core.openstack-service-api.magnum'
];
/*
* @ngdoc factory
* @name horizon.dashboard.container-infra.quotas.service
*
* @description
* This service provides functions that are used through the Quotas
* features. These are primarily used in the module registrations
* but do not need to be restricted to such use. Each exposed function
* is documented below.
*/
function quotasService($filter, magnum) {
return {
getQuotasPromise: getQuotasPromise
};
function getQuotasPromise(params) {
return magnum.getQuotas(params).then(modifyResponse);
function modifyResponse(response) {
return {data: {items: response.data.items.map(addTrackBy)}};
function addTrackBy(quota) {
quota.trackBy = quota.id + quota.resource;
return quota;
}
}
}
}
})();

View File

@ -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('quotas service', function() {
var magnum, service;
beforeEach(module('horizon.framework'));
beforeEach(module('horizon.app.core.openstack-service-api'));
beforeEach(module('horizon.dashboard.container-infra.quotas'));
beforeEach(inject(function($injector) {
magnum = $injector.get('horizon.app.core.openstack-service-api.magnum');
service = $injector.get('horizon.dashboard.container-infra.quotas.service');
}));
describe('getQuotasPromise', function() {
it("provides a promise", inject(function($q, $timeout) {
var deferred = $q.defer();
spyOn(magnum, 'getQuotas').and.returnValue(deferred.promise);
var result = service.getQuotasPromise({});
deferred.resolve({
data:{
items: [{id: '123', resource: 'Cluster', hard_limit: 5}]
}
});
$timeout.flush();
expect(magnum.getQuotas).toHaveBeenCalled();
expect(result.$$state.value.data.items[0].id).toBe('123');
}));
});
});
})();