diff --git a/horizon/static/framework/widgets/table/table.scss b/horizon/static/framework/widgets/table/table.scss
index 3884077af1..a6b0f04eb4 100644
--- a/horizon/static/framework/widgets/table/table.scss
+++ b/horizon/static/framework/widgets/table/table.scss
@@ -288,9 +288,11 @@ $em-per-priority: floor($table-col-avg-width / $font-size-base) * 3;
display: none;
}
- .rsp-alt-p1, .rsp-alt-p2,
- .rsp-alt-p3, .rsp-alt-p4 {
- display: inline-block;
+ th,td {
+ &.rsp-alt-p1, &.rsp-alt-p2,
+ &.rsp-alt-p3, &.rsp-alt-p4 {
+ display: inline-block;
+ }
}
}
diff --git a/openstack_dashboard/dashboards/project/ngimages/templates/ngimages/index.html b/openstack_dashboard/dashboards/project/ngimages/templates/ngimages/index.html
index ee9c0dde54..d9abdb78ec 100644
--- a/openstack_dashboard/dashboards/project/ngimages/templates/ngimages/index.html
+++ b/openstack_dashboard/dashboards/project/ngimages/templates/ngimages/index.html
@@ -8,4 +8,5 @@
{% endblock page_header %}
{% block main %}
+
{% endblock %}
diff --git a/openstack_dashboard/dashboards/project/static/dashboard/project/images/images.module.js b/openstack_dashboard/dashboards/project/static/dashboard/project/images/images.module.js
new file mode 100644
index 0000000000..b0ef86d9ed
--- /dev/null
+++ b/openstack_dashboard/dashboards/project/static/dashboard/project/images/images.module.js
@@ -0,0 +1,46 @@
+/**
+ * (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 hz.dashboard.project.images
+ *
+ * @description
+ * Provides the services and widgets required
+ * to support and display the project images panel.
+ */
+ angular
+ .module('hz.dashboard.project.images', [])
+ .config(config);
+
+ config.$inject = [
+ '$provide',
+ '$windowProvider'
+ ];
+
+ /**
+ * @name hz.dashboard.project.images.basePath
+ * @description Base path for the project dashboard
+ */
+ function config($provide, $windowProvider) {
+ var path = $windowProvider.$get().STATIC_URL + 'dashboard/project/images/';
+ $provide.constant('hz.dashboard.project.images.basePath', path);
+ }
+
+})();
diff --git a/openstack_dashboard/dashboards/project/static/dashboard/project/images/images.module.spec.js b/openstack_dashboard/dashboards/project/static/dashboard/project/images/images.module.spec.js
new file mode 100644
index 0000000000..e07b22c306
--- /dev/null
+++ b/openstack_dashboard/dashboards/project/static/dashboard/project/images/images.module.spec.js
@@ -0,0 +1,45 @@
+/**
+ * (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('hz.dashboard.project.images', function() {
+ it('should exist', function() {
+ expect(angular.module('hz.dashboard.project.images')).toBeDefined();
+ });
+ });
+
+ describe('hz.dashboard.project.images.basePath constant', function () {
+ var imagesBasePath, staticUrl;
+
+ beforeEach(module('hz.dashboard'));
+ beforeEach(module('hz.dashboard.project'));
+ beforeEach(module('hz.dashboard.project.images'));
+ beforeEach(inject(function ($injector) {
+ imagesBasePath = $injector.get('hz.dashboard.project.images.basePath');
+ staticUrl = $injector.get('$window').STATIC_URL;
+ }));
+
+ it('should be defined', function () {
+ expect(imagesBasePath).toBeDefined();
+ });
+
+ it('should equal to "/static/dashboard/project/images/"', function () {
+ expect(imagesBasePath).toEqual(staticUrl + 'dashboard/project/images/');
+ });
+ });
+
+})();
diff --git a/openstack_dashboard/dashboards/project/static/dashboard/project/project.module.js b/openstack_dashboard/dashboards/project/static/dashboard/project/project.module.js
index c2c03d47d2..d05d0d7123 100644
--- a/openstack_dashboard/dashboards/project/static/dashboard/project/project.module.js
+++ b/openstack_dashboard/dashboards/project/static/dashboard/project/project.module.js
@@ -18,12 +18,28 @@
'use strict';
/**
- * @ngdoc hz.dashboard.project
- * @ngModule
+ * @ngdoc overview
+ * @ngname hz.dashboard.project
+ *
* @description
* Dashboard module to host project panels.
*/
angular
- .module('hz.dashboard.project', []);
+ .module('hz.dashboard.project', ['hz.dashboard.project.images'])
+ .config(config);
+
+ config.$inject = [
+ '$provide',
+ '$windowProvider'
+ ];
+
+ /**
+ * @name hz.dashboard.project.basePath
+ * @description Base path for the project dashboard
+ */
+ function config($provide, $windowProvider) {
+ var path = $windowProvider.$get().STATIC_URL + 'dashboard/project/';
+ $provide.constant('hz.dashboard.project.basePath', path);
+ }
})();
diff --git a/openstack_dashboard/dashboards/project/static/dashboard/project/project.module.spec.js b/openstack_dashboard/dashboards/project/static/dashboard/project/project.module.spec.js
index 77008c7529..055874b91c 100644
--- a/openstack_dashboard/dashboards/project/static/dashboard/project/project.module.spec.js
+++ b/openstack_dashboard/dashboards/project/static/dashboard/project/project.module.spec.js
@@ -22,4 +22,23 @@
});
});
+ describe('hz.dashboard.project.basePath constant', function () {
+ var projectBasePath, staticUrl;
+
+ beforeEach(module('hz.dashboard'));
+ beforeEach(module('hz.dashboard.project'));
+ beforeEach(inject(function ($injector) {
+ projectBasePath = $injector.get('hz.dashboard.project.basePath');
+ staticUrl = $injector.get('$window').STATIC_URL;
+ }));
+
+ it('should be defined', function () {
+ expect(projectBasePath).toBeDefined();
+ });
+
+ it('should equal to "/static/dashboard/project/"', function () {
+ expect(projectBasePath).toEqual(staticUrl + 'dashboard/project/');
+ });
+ });
+
})();
diff --git a/openstack_dashboard/static/app/core/core.module.js b/openstack_dashboard/static/app/core/core.module.js
index aab3eba86b..f2f5c608f1 100644
--- a/openstack_dashboard/static/app/core/core.module.js
+++ b/openstack_dashboard/static/app/core/core.module.js
@@ -28,6 +28,7 @@
*/
angular
.module('horizon.app.core', [
+ 'horizon.app.core.images',
'horizon.app.core.workflow'
]);
diff --git a/openstack_dashboard/static/app/core/core.scss b/openstack_dashboard/static/app/core/core.scss
new file mode 100644
index 0000000000..c46c3bf362
--- /dev/null
+++ b/openstack_dashboard/static/app/core/core.scss
@@ -0,0 +1 @@
+@import "images/images";
diff --git a/openstack_dashboard/static/app/core/images/filters/image-status.filter.js b/openstack_dashboard/static/app/core/images/filters/image-status.filter.js
new file mode 100644
index 0000000000..38b3b313f3
--- /dev/null
+++ b/openstack_dashboard/static/app/core/images/filters/image-status.filter.js
@@ -0,0 +1,49 @@
+/**
+ * (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'
+ ];
+
+ /**
+ * @ngdoc filter
+ * @name imageStatusFilter
+ * @description
+ * Takes raw image status from the API and returns the user friendly status.
+ */
+ 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 function (input) {
+ var result = imageStatuses[input];
+ return angular.isDefined(result) ? result : input;
+ };
+ }
+
+}());
diff --git a/openstack_dashboard/static/app/core/images/filters/image-status.filter.spec.js b/openstack_dashboard/static/app/core/images/filters/image-status.filter.spec.js
new file mode 100644
index 0000000000..d4c281f682
--- /dev/null
+++ b/openstack_dashboard/static/app/core/images/filters/image-status.filter.spec.js
@@ -0,0 +1,40 @@
+/**
+ * (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');
+ });
+
+ });
+
+ });
+})();
diff --git a/openstack_dashboard/static/app/core/images/filters/image-type.filter.js b/openstack_dashboard/static/app/core/images/filters/image-type.filter.js
new file mode 100644
index 0000000000..aac16e4ef3
--- /dev/null
+++ b/openstack_dashboard/static/app/core/images/filters/image-type.filter.js
@@ -0,0 +1,46 @@
+/**
+ * (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'
+ ];
+
+ /**
+ * @ngdoc filter
+ * @name imageTypeFilter
+ * @description
+ * Takes a raw image object from the API and returns the user friendly type.
+ */
+ function imageTypeFilter(gettext) {
+ return function (input) {
+ if (null !== input &&
+ angular.isDefined(input) &&
+ angular.isDefined(input.properties) &&
+ input.properties.image_type === 'snapshot') {
+ return gettext('Snapshot');
+ } else {
+ return gettext('Image');
+ }
+ };
+ }
+
+}());
diff --git a/openstack_dashboard/static/app/core/images/filters/image-type.filter.spec.js b/openstack_dashboard/static/app/core/images/filters/image-type.filter.spec.js
new file mode 100644
index 0000000000..38eb962ed9
--- /dev/null
+++ b/openstack_dashboard/static/app/core/images/filters/image-type.filter.spec.js
@@ -0,0 +1,48 @@
+/**
+ * (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(undefined)).toBe('Image');
+ });
+
+ });
+
+ });
+})();
diff --git a/openstack_dashboard/static/app/core/images/images.module.js b/openstack_dashboard/static/app/core/images/images.module.js
new file mode 100644
index 0000000000..d047accb19
--- /dev/null
+++ b/openstack_dashboard/static/app/core/images/images.module.js
@@ -0,0 +1,46 @@
+/**
+ * (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.images
+ *
+ * @description
+ * Provides all of the services and widgets required
+ * to support and display images related content.
+ */
+ angular
+ .module('horizon.app.core.images', [])
+ .config(config);
+
+ config.$inject = [
+ '$provide',
+ '$windowProvider'
+ ];
+
+ /**
+ * @name horizon.app.core.images.basePath
+ * @description Base path for the images code
+ */
+ function config($provide, $windowProvider) {
+ var path = $windowProvider.$get().STATIC_URL + 'app/core/images/';
+ $provide.constant('horizon.app.core.images.basePath', path);
+ }
+
+})();
diff --git a/openstack_dashboard/static/app/core/images/images.module.spec.js b/openstack_dashboard/static/app/core/images/images.module.spec.js
new file mode 100644
index 0000000000..f0c1507c6f
--- /dev/null
+++ b/openstack_dashboard/static/app/core/images/images.module.spec.js
@@ -0,0 +1,44 @@
+/**
+ * (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', function () {
+ it('should exist', function () {
+ expect(angular.module('horizon.app.core.images')).toBeDefined();
+ });
+ });
+
+ describe('horizon.app.core.images.basePath constant', function () {
+ var imagesBasePath, staticUrl;
+
+ beforeEach(module('horizon.app.core'));
+ beforeEach(module('horizon.app.core.images'));
+ beforeEach(inject(function ($injector) {
+ imagesBasePath = $injector.get('horizon.app.core.images.basePath');
+ staticUrl = $injector.get('$window').STATIC_URL;
+ }));
+
+ it('should be defined', function () {
+ expect(imagesBasePath).toBeDefined();
+ });
+
+ it('should equal to "/static/app/core/images/"', function () {
+ expect(imagesBasePath).toEqual(staticUrl + 'app/core/images/');
+ });
+ });
+
+})();
diff --git a/openstack_dashboard/static/app/core/images/images.scss b/openstack_dashboard/static/app/core/images/images.scss
new file mode 100644
index 0000000000..6dc13f4549
--- /dev/null
+++ b/openstack_dashboard/static/app/core/images/images.scss
@@ -0,0 +1,11 @@
+table[ng-controller="imagesTableController as table"] {
+
+ .detail-expanded .row {
+ background: none;
+ padding-left: 2em;
+ }
+
+ &.table-rsp .action-col {
+ min-width: 12em;
+ }
+}
diff --git a/openstack_dashboard/static/app/core/images/table/images-table-batch-actions.html b/openstack_dashboard/static/app/core/images/table/images-table-batch-actions.html
new file mode 100644
index 0000000000..bfcba21cbb
--- /dev/null
+++ b/openstack_dashboard/static/app/core/images/table/images-table-batch-actions.html
@@ -0,0 +1,10 @@
+
+
+
\ No newline at end of file
diff --git a/openstack_dashboard/static/app/core/images/table/images-table.controller.js b/openstack_dashboard/static/app/core/images/table/images-table.controller.js
new file mode 100644
index 0000000000..17706149d2
--- /dev/null
+++ b/openstack_dashboard/static/app/core/images/table/images-table.controller.js
@@ -0,0 +1,61 @@
+/**
+ * (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 controller
+ * @name ImagesTableController
+ *
+ * @description
+ * Controller for the images table.
+ * Serves as the focal point for table actions.
+ */
+ angular
+ .module('horizon.app.core.images')
+ .controller('imagesTableController', ImagesTableController);
+
+ ImagesTableController.$inject = [
+ 'horizon.app.core.images.basePath',
+ 'horizon.openstack-service-api.glance'
+ ];
+
+ function ImagesTableController(basepath, glance) {
+
+ var ctrl = this;
+ ctrl.images = [];
+ ctrl.imagesSrc = [];
+ ctrl.checked = {};
+ ctrl.path = basepath + 'table/';
+
+ init();
+
+ ////////////////////////////////
+
+ function init() {
+ // if user has permission
+ // fetch table data and populate it
+ glance.getImages().success(onGetImages);
+ }
+
+ function onGetImages(response) {
+ ctrl.imagesSrc = response.items;
+ }
+
+ }
+
+})();
diff --git a/openstack_dashboard/static/app/core/images/table/images-table.controller.spec.js b/openstack_dashboard/static/app/core/images/table/images-table.controller.spec.js
new file mode 100644
index 0000000000..e20cca1f7d
--- /dev/null
+++ b/openstack_dashboard/static/app/core/images/table/images-table.controller.spec.js
@@ -0,0 +1,68 @@
+/**
+ * (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 table controller', function() {
+
+ function fakeGlance() {
+ return {
+ success: function(callback) {
+ callback({
+ items : []
+ });
+ }
+ };
+ }
+
+ var controller, glanceAPI, staticUrl;
+
+ ///////////////////////
+
+ beforeEach(module('horizon.framework.util.http'));
+ beforeEach(module('horizon.framework.widgets.toast'));
+ beforeEach(module('horizon.openstack-service-api'));
+
+ beforeEach(module('horizon.app.core'));
+ beforeEach(module('horizon.app.core.images'));
+ beforeEach(inject(function($injector) {
+
+ glanceAPI = $injector.get('horizon.openstack-service-api.glance');
+ controller = $injector.get('$controller');
+ staticUrl = $injector.get('$window').STATIC_URL;
+
+ spyOn(glanceAPI, 'getImages').and.callFake(fakeGlance);
+ }));
+
+ function createController() {
+ return controller('imagesTableController', {
+ glanceAPI: glanceAPI
+ });
+ }
+
+ it('should set path properly', function() {
+ var path = staticUrl + 'app/core/images/table/';
+ expect(createController().path).toEqual(path);
+ });
+
+ it('should invoke glance apis', function() {
+ createController();
+ expect(glanceAPI.getImages).toHaveBeenCalled();
+ });
+
+ });
+})();
diff --git a/openstack_dashboard/static/app/core/images/table/images-table.html b/openstack_dashboard/static/app/core/images/table/images-table.html
new file mode 100644
index 0000000000..bc8c8dd897
--- /dev/null
+++ b/openstack_dashboard/static/app/core/images/table/images-table.html
@@ -0,0 +1,18 @@
+