Merge "Image uses hz-property for its drawer information"

This commit is contained in:
Jenkins 2016-07-20 23:08:41 +00:00 committed by Gerrit Code Review
commit 97123bdd93
9 changed files with 216 additions and 275 deletions

View File

@ -1,34 +1,14 @@
<div ng-controller="horizon.app.core.images.DrawerController as drawerCtrl">
<div class="row">
<dl class="col-md-2">
<dt translate>Is Public</dt>
<dd>{$ item.is_public | yesno $}</dd>
</dl>
<dl class="col-md-2">
<dt translate>Protected</dt>
<dd>{$ item.protected | yesno $}</dd>
</dl>
<dl class="col-md-2">
<dt translate>Format</dt>
<dd>{$ item.disk_format | noValue | uppercase $}</dd>
</dl>
<dl class="col-md-2">
<dt translate>Size</dt>
<dd>{$ item.size | bytes $}</dd>
</dl>
</div>
<div class="row">
<dl class="col-md-2">
<dt translate>Min. Disk</dt>
<dd>{$ item.min_disk | gb | noValue $}</dd>
</dl>
<dl class="col-md-2">
<dt translate>Min. RAM</dt>
<dd>{$ item.min_ram | mb | noValue $}</dd>
</dl>
</div>
<hz-resource-property-list
resource-type-name="OS::Glance::Image"
item="item"
property-groups="[
['name', 'id'],
['is_public', 'protected'],
['disk_format', 'size'],
['min_disk', 'min_ram']]">
</hz-resource-property-list>
<div class="row" ng-if="drawerCtrl.metadataDefs">
<div class="col-sm-12">

View File

@ -3,29 +3,21 @@
<div class="col-md-6 detail">
<h3 translate>Image</h3>
<hr>
<dl class="dl-horizontal">
<dt translate>Type</dt>
<dd>{$ ctrl.image | imageType $}</dd>
<dt translate>Filename</dt>
<dd>{$ ctrl.image.properties.filename $}</dd>
<dt translate>Status</dt>
<dd>{$ ctrl.image.status $}</dd>
<dt translate>Size</dt>
<dd>{$ ctrl.image.size | bytes $}</dd>
<dt translate>Min. Disk</dt>
<dd>{$ ctrl.image.min_disk | gb $}</dd>
<dt translate>Min. RAM</dt>
<dd>{$ ctrl.image.min_ram | mb $}</dd>
<dt translate>Disk Format</dt>
<dd>{$ ctrl.image.disk_format | uppercase $}</dd>
<dt translate>Container Format</dt>
<dd>{$ ctrl.image.container_format | uppercase $}</dd>
</dl>
<hz-resource-property-list
resource-type-name="OS::Glance::Image"
cls="dl-horizontal"
item="ctrl.image"
property-groups="[[
'type', 'status', 'size', 'min_disk', 'min_ram', 'disk_format',
'container_format']]">
</hz-resource-property-list>
</div>
<div class="col-md-6 detail">
<h3>{$ 'Security' | translate $}</h3>
<hr>
<dl class="dl-horizontal">
<dt translate>Filename</dt>
<dd>{$ ctrl.image.properties.filename $}</dd>
<dt translate>Visibility</dt>
<dd>{$ ctrl.image | imageVisibility $}</dd>
<dt translate>Protected</dt>

View File

@ -1,53 +0,0 @@
/**
* (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';
angular
.module('horizon.app.core.images')
.filter('imageStatus', imageStatusFilter);
imageStatusFilter.$inject = [
'horizon.framework.util.i18n.gettext'
];
function imageStatusFilter(gettext) {
var imageStatuses = {
'active': gettext('Active'),
'saving': gettext('Saving'),
'queued': gettext('Queued'),
'pending_delete': gettext('Pending Delete'),
'killed': gettext('Killed'),
'deleted': gettext('Deleted')
};
return filter;
/**
* @ngdoc filter
* @name imageStatusFilter
* @param {string} input - The status code
* @description
* Takes raw image status from the API and returns the user friendly status.
* @returns {string} The user-friendly status
*/
function filter(input) {
var result = imageStatuses[input];
return angular.isDefined(result) ? result : input;
}
}
}());

View File

@ -1,40 +0,0 @@
/**
* (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';
describe('horizon.app.core.images.imageStatus Filter', function () {
beforeEach(module('horizon.framework.util.i18n'));
beforeEach(module('horizon.app.core.images'));
describe('iumageStatus', function () {
var imageStatusFilter;
beforeEach(inject(function (_imageStatusFilter_) {
imageStatusFilter = _imageStatusFilter_;
}));
it('Returns value when key is present', function () {
expect(imageStatusFilter('active')).toBe('Active');
});
it('Returns input when key is not present', function () {
expect(imageStatusFilter('unknown')).toBe('unknown');
});
});
});
})();

View File

@ -1,50 +0,0 @@
/**
* (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';
angular
.module('horizon.app.core.images')
.filter('imageType', imageTypeFilter);
imageTypeFilter.$inject = [
'horizon.framework.util.i18n.gettext'
];
function imageTypeFilter(gettext) {
return filter;
/**
* @ngdoc filter
* @name imageTypeFilter
* @param {Object} input - An image object
* @description
* Takes a raw image object from the API and returns the user friendly type.
* @returns {Function} The filter
*/
function filter(input) {
if (null !== input &&
angular.isDefined(input) &&
angular.isDefined(input.properties) &&
input.properties.image_type === 'snapshot') {
return gettext('Snapshot');
} else {
return gettext('Image');
}
}
}
}());

View File

@ -1,48 +0,0 @@
/**
* (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';
describe('horizon.app.core.images.imageType Filter', function () {
beforeEach(module('horizon.framework.util.i18n'));
beforeEach(module('horizon.app.core.images'));
describe('imageType', function () {
var imageTypeFilter;
beforeEach(inject(function (_imageTypeFilter_) {
imageTypeFilter = _imageTypeFilter_;
}));
it('returns Snapshot for snapshot', function () {
expect(imageTypeFilter({properties:{image_type:'snapshot'}})).toBe('Snapshot');
});
it('returns Image for image', function () {
expect(imageTypeFilter({properties:{image_type:'image'}})).toBe('Image');
});
it('returns Image for null', function () {
expect(imageTypeFilter(null)).toBe('Image');
});
it('returns Image for undefined', function () {
expect(imageTypeFilter()).toBe('Image');
});
});
});
})();

View File

@ -36,17 +36,26 @@
.constant('horizon.app.core.images.validationRules', validationRules())
.constant('horizon.app.core.images.imageFormats', imageFormats())
.constant('horizon.app.core.images.resourceType', 'OS::Glance::Image')
.constant('horizon.app.core.images.statuses', {
'active': gettext('Active'),
'saving': gettext('Saving'),
'queued': gettext('Queued'),
'pending_delete': gettext('Pending Delete'),
'killed': gettext('Killed'),
'deleted': gettext('Deleted')
})
.run(run)
.config(config);
run.$inject = [
'horizon.framework.conf.resource-type-registry.service',
'horizon.app.core.openstack-service-api.glance',
'horizon.app.core.images.basePath',
'horizon.app.core.images.service',
'horizon.app.core.images.statuses',
'horizon.app.core.images.resourceType'
];
function run(registry, glance, basePath, imageResourceType) {
function run(registry, basePath, imagesService, statuses, imageResourceType) {
registry.getResourceType(imageResourceType)
.setNames(gettext('Image'), gettext('Images'))
.setSummaryTemplateUrl(basePath + 'details/drawer.html')
@ -54,19 +63,26 @@
label: gettext('Checksum')
})
.setProperty('container_format', {
label: gettext('Container Format')
label: gettext('Container Format'),
filters: ['uppercase']
})
.setProperty('created_at', {
label: gettext('Created At')
})
.setProperty('disk_format', {
label: gettext('Disk Format')
label: gettext('Disk Format'),
filters: ['noValue', 'uppercase']
})
.setProperty('id', {
label: gettext('ID')
})
.setProperty('is_public', {
label: gettext('Is Public'),
filters: ['yesno']
})
.setProperty('type', {
label: gettext('Type')
label: gettext('Type'),
filters: [imagesService.imageType]
})
.setProperty('members', {
label: gettext('Members')
@ -84,13 +100,16 @@
label: gettext('Owner')
})
.setProperty('protected', {
label: gettext('Protected')
label: gettext('Protected'),
filters: ['yesno']
})
.setProperty('size', {
label: gettext('Size')
label: gettext('Size'),
filters: ['bytes']
})
.setProperty('status', {
label: gettext('Status')
label: gettext('Status'),
values: statuses
})
.setProperty('tags', {
label: gettext('Tags')
@ -116,38 +135,33 @@
.setProperty('ramdisk_id', {
label: gettext('Ramdisk ID')
})
.setListFunction(listFunction)
.setListFunction(imagesService.getImagesPromise)
.tableColumns
.append({
id: 'name',
priority: 1,
sortDefault: true,
urlFunction: urlFunction
urlFunction: imagesService.getDetailsPath
})
.append({
id: 'type',
priority: 1,
filters: ['imageType']
priority: 1
})
.append({
id: 'status',
priority: 1,
filters: ['imageStatus']
priority: 1
})
.append({
id: 'protected',
priority: 1,
filters: ['yesno']
priority: 1
})
.append({
id: 'disk_format',
priority: 2,
filters: ['noValue', 'uppercase']
priority: 2
})
.append({
id: 'size',
priority: 2,
filters: ['bytes']
priority: 2
});
registry.getResourceType(imageResourceType).filterFacets
@ -214,23 +228,6 @@
isServer: true,
singleton: true
});
function listFunction(params) {
return glance.getImages(params).then(modifyResponse);
function modifyResponse(response) {
return {data: {items: response.data.items.map(addTrackBy)}};
function addTrackBy(image) {
image.trackBy = image.id + image.updated_at;
return image;
}
}
}
function urlFunction(item) {
return 'project/ngdetails/OS::Glance::Image/' + item.id;
}
}
/**

View File

@ -0,0 +1,97 @@
/*
* (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.images')
.factory('horizon.app.core.images.service', imageService);
imageService.$inject = [
'horizon.app.core.openstack-service-api.glance'
];
/*
* @ngdoc factory
* @name horizon.app.core.images.service
*
* @description
* This service provides functions that are used through the Images
* 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 imageService(glance) {
return {
getDetailsPath: getDetailsPath,
getImagesPromise: getImagesPromise,
imageType: imageType
};
/*
* @ngdoc function
* @name getDetailsPath
* @param item {Object} - The image object
* @description
* Given an Image object, returns the relative path to the details
* view.
*/
function getDetailsPath(item) {
return 'project/ngdetails/OS::Glance::Image/' + item.id;
}
/*
* @ngdoc function
* @name imageType
* @param item {Object} - The image object
* @description
* Given an Image object, returns a name describing the type of image,
* either an 'Image' or a 'Snapshot' type.
*/
function imageType(item) {
if (null !== item &&
angular.isDefined(item) &&
angular.isDefined(item.properties) &&
item.properties.image_type === 'snapshot') {
return gettext('Snapshot');
} else {
return gettext('Image');
}
}
/*
* @ngdoc function
* @name getImagesPromise
* @description
* Given filter/query parameters, returns a promise for the matching
* images. This is used in displaying lists of Images. In this case,
* we need to modify the API's response by adding a composite value called
* 'trackBy' to assist the display mechanism when updating rows.
*/
function getImagesPromise(params) {
return glance.getImages(params).then(modifyResponse);
function modifyResponse(response) {
return {data: {items: response.data.items.map(addTrackBy)}};
function addTrackBy(image) {
image.trackBy = image.id + image.updated_at;
return image;
}
}
}
}
})();

View File

@ -0,0 +1,66 @@
/*
* (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('images service', function() {
var service;
beforeEach(module('horizon.app.core.images'));
beforeEach(inject(function($injector) {
service = $injector.get('horizon.app.core.images.service');
}));
it("getDetailsPath creates urls using the item's ID", function() {
var myItem = {id: "1234"};
expect(service.getDetailsPath(myItem)).toBe('project/ngdetails/OS::Glance::Image/1234');
});
describe('imageType', function() {
it("imageType returns Snapshot when appropriate", function() {
var myItem = {properties: {image_type: 'snapshot'}};
expect(service.imageType(myItem)).toBe('Snapshot');
});
it("imageType returns Image when no item", function() {
var myItem;
expect(service.imageType(myItem)).toBe('Image');
});
it("imageType returns Image when no properties", function() {
var myItem = {};
expect(service.imageType(myItem)).toBe('Image');
});
it("imageType returns Image when properties but not type 'snapshot'", function() {
var myItem = {properties: {image_type: 'unknown'}};
expect(service.imageType(myItem)).toBe('Image');
});
});
describe('getImagesPromise', function() {
it("provides a promise that gets translated", inject(function($q, $injector, $timeout) {
var glance = $injector.get('horizon.app.core.openstack-service-api.glance');
var deferred = $q.defer();
spyOn(glance, 'getImages').and.returnValue(deferred.promise);
var result = service.getImagesPromise({});
deferred.resolve({data: {items: [{id: 1, updated_at: 'jul1'}]}});
$timeout.flush();
expect(result.$$state.value.data.items[0].trackBy).toBe('1jul1');
}));
});
});
})();