Adding resource panel and table features
This patch adds two basic features: a directive that takes in a resource type name and produces a table of the resource type with actions, links to views, etc., based on information in the resource type object; the other directive provides a resource panel with header based on a resource type name. Change-Id: Idaba844aca5fc6e89e2bd7c65cb836feaba67f67 Partially-Implements: blueprint angular-registry
This commit is contained in:
parent
947b9f5b42
commit
01aa99473a
@ -94,7 +94,9 @@
|
|||||||
// type, with the data as a result in a promise. For example, Images code
|
// type, with the data as a result in a promise. For example, Images code
|
||||||
// would register a list function that returns a promise that will resolve
|
// would register a list function that returns a promise that will resolve
|
||||||
// to all the Images data in list form.
|
// to all the Images data in list form.
|
||||||
this.listFunction = angular.noop;
|
this.listFunction = function def() {
|
||||||
|
return Promise.resolve({data: {items: []}});
|
||||||
|
};
|
||||||
this.setListFunction = setListFunction;
|
this.setListFunction = setListFunction;
|
||||||
|
|
||||||
// The table columns are an extensible registration of columns of data
|
// The table columns are an extensible registration of columns of data
|
||||||
@ -506,10 +508,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
var resourceTypes = {};
|
var resourceTypes = {};
|
||||||
// The slugs are only used to align Django routes with heat
|
|
||||||
// type names. In a context without Django routing this is
|
|
||||||
// not needed.
|
|
||||||
var slugs = {};
|
|
||||||
var defaultSummaryTemplateUrl = false;
|
var defaultSummaryTemplateUrl = false;
|
||||||
var defaultDetailsTemplateUrl = false;
|
var defaultDetailsTemplateUrl = false;
|
||||||
var registry = {
|
var registry = {
|
||||||
@ -519,20 +517,9 @@
|
|||||||
setDefaultSummaryTemplateUrl: setDefaultSummaryTemplateUrl,
|
setDefaultSummaryTemplateUrl: setDefaultSummaryTemplateUrl,
|
||||||
getDefaultSummaryTemplateUrl: getDefaultSummaryTemplateUrl,
|
getDefaultSummaryTemplateUrl: getDefaultSummaryTemplateUrl,
|
||||||
setDefaultDetailsTemplateUrl: setDefaultDetailsTemplateUrl,
|
setDefaultDetailsTemplateUrl: setDefaultDetailsTemplateUrl,
|
||||||
getDefaultDetailsTemplateUrl: getDefaultDetailsTemplateUrl,
|
getDefaultDetailsTemplateUrl: getDefaultDetailsTemplateUrl
|
||||||
setSlug: setSlug,
|
|
||||||
getTypeNameBySlug: getTypeNameBySlug
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function getTypeNameBySlug(slug) {
|
|
||||||
return slugs[slug];
|
|
||||||
}
|
|
||||||
|
|
||||||
function setSlug(slug, typeName) {
|
|
||||||
slugs[slug] = typeName;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDefaultSummaryTemplateUrl() {
|
function getDefaultSummaryTemplateUrl() {
|
||||||
return defaultSummaryTemplateUrl;
|
return defaultSummaryTemplateUrl;
|
||||||
}
|
}
|
||||||
|
@ -166,11 +166,6 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("sets and retrieves slugs", function() {
|
|
||||||
service.setSlug('image', 'OS::Glance::Image');
|
|
||||||
expect(service.getTypeNameBySlug('image')).toBe('OS::Glance::Image');
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getName', function() {
|
describe('getName', function() {
|
||||||
it('returns nothing if names not provided', function() {
|
it('returns nothing if names not provided', function() {
|
||||||
var type = service.getResourceType('something');
|
var type = service.getResourceType('something');
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* (c) Copyright 2016 Hewlett Packard Enterprise Development Company 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.framework.widgets.panel')
|
||||||
|
.controller('horizon.framework.widgets.panel.HzResourcePanelController', controller);
|
||||||
|
|
||||||
|
controller.$inject = [
|
||||||
|
'horizon.framework.conf.resource-type-registry.service'
|
||||||
|
];
|
||||||
|
|
||||||
|
function controller(registry) {
|
||||||
|
var ctrl = this;
|
||||||
|
|
||||||
|
ctrl.resourceType = registry.getResourceType(ctrl.resourceTypeName);
|
||||||
|
ctrl.pageName = ctrl.resourceType.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
})();
|
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* (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-resource-panel controller', function() {
|
||||||
|
var ctrl;
|
||||||
|
|
||||||
|
var resourceType = {
|
||||||
|
getName: function() {
|
||||||
|
return 'MyType';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(module('horizon.framework.conf'));
|
||||||
|
beforeEach(module('horizon.framework.widgets.panel'));
|
||||||
|
|
||||||
|
beforeEach(inject(function($controller) {
|
||||||
|
var registry = {
|
||||||
|
getResourceType: angular.noop
|
||||||
|
};
|
||||||
|
|
||||||
|
spyOn(registry, 'getResourceType').and.returnValue(resourceType);
|
||||||
|
|
||||||
|
ctrl = $controller('horizon.framework.widgets.panel.HzResourcePanelController', {
|
||||||
|
'horizon.framework.conf.resource-type-registry.service': registry,
|
||||||
|
tableResourceType: 'OS::Test::Example'});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('exists', function() {
|
||||||
|
expect(ctrl).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets resourceType to the resource type', function() {
|
||||||
|
expect(ctrl.resourceType).toBe(resourceType);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets resourceTypeName to the resource type name', function() {
|
||||||
|
expect(ctrl.pageName).toEqual('MyType');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
})();
|
@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* (c) Copyright 2016 Hewlett Packard Enterprise Development Company 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.framework.widgets.panel')
|
||||||
|
.directive('hzResourcePanel', directive);
|
||||||
|
|
||||||
|
directive.$inject = ['horizon.framework.widgets.basePath'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc directive
|
||||||
|
* @name hzResourcePanel
|
||||||
|
* @description
|
||||||
|
* This directive takes in a resource type name, e.g. 'OS::Glance::Image'
|
||||||
|
* as a String and produces the shell of a panel for that given resource
|
||||||
|
* type. This primarily includes a header and allows content to be
|
||||||
|
* transcluded.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
```
|
||||||
|
<hz-resource-panel resource-type-name="OS::Nova::Server">
|
||||||
|
<div>Here is my content!</div>
|
||||||
|
<hz-resource-table resource-type-name="OS::Nova::Server"></hz-resource-table>
|
||||||
|
</hz-resource-panel>
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
function directive(basePath) {
|
||||||
|
|
||||||
|
var directive = {
|
||||||
|
restrict: 'E',
|
||||||
|
scope: {
|
||||||
|
resourceTypeName: '@'
|
||||||
|
},
|
||||||
|
transclude: true,
|
||||||
|
bindToController: true,
|
||||||
|
templateUrl: basePath + 'panel/hz-resource-panel.html',
|
||||||
|
controller: "horizon.framework.widgets.panel.HzResourcePanelController as ctrl"
|
||||||
|
};
|
||||||
|
|
||||||
|
return directive;
|
||||||
|
}
|
||||||
|
})();
|
@ -0,0 +1,4 @@
|
|||||||
|
<div>
|
||||||
|
<hz-page-header header="{$ ctrl.pageName $}"></hz-page-header>
|
||||||
|
<ng-transclude></ng-transclude>
|
||||||
|
</div>
|
22
horizon/static/framework/widgets/panel/panel.module.js
Normal file
22
horizon/static/framework/widgets/panel/panel.module.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* (c) Copyright 2016 Hewlett Packard Enterprise Development Company 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.framework.widgets.panel', []);
|
||||||
|
|
||||||
|
})();
|
@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* (c) Copyright 2016 Hewlett Packard Enterprise Development Company 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.framework.widgets.table')
|
||||||
|
.controller('horizon.framework.widgets.table.ResourceTableController', controller);
|
||||||
|
|
||||||
|
controller.$inject = [
|
||||||
|
'$q',
|
||||||
|
'$scope',
|
||||||
|
'horizon.framework.util.actions.action-result.service',
|
||||||
|
'horizon.framework.conf.resource-type-registry.service'
|
||||||
|
];
|
||||||
|
|
||||||
|
function controller($q, $scope, actionResultService, registry) {
|
||||||
|
var ctrl = this;
|
||||||
|
|
||||||
|
// 'Public' Controller members
|
||||||
|
|
||||||
|
ctrl.resourceType = registry.getResourceType(ctrl.resourceTypeName);
|
||||||
|
ctrl.items = [];
|
||||||
|
ctrl.itemsSrc = [];
|
||||||
|
ctrl.searchFacets = [];
|
||||||
|
ctrl.config = {
|
||||||
|
detailsTemplateUrl: ctrl.resourceType.summaryTemplateUrl,
|
||||||
|
selectAll: true,
|
||||||
|
expand: true,
|
||||||
|
trackId: 'id',
|
||||||
|
searchColumnSpan: 6,
|
||||||
|
actionColumnSpan: 6,
|
||||||
|
columns: ctrl.resourceType.getTableColumns()
|
||||||
|
};
|
||||||
|
ctrl.batchActions = ctrl.resourceType.globalActions
|
||||||
|
.concat(ctrl.resourceType.batchActions);
|
||||||
|
|
||||||
|
ctrl.actionResultHandler = actionResultHandler;
|
||||||
|
|
||||||
|
// Controller Initialization/Loading
|
||||||
|
|
||||||
|
ctrl.resourceType.listFunction().then(onLoad);
|
||||||
|
registry.initActions(ctrl.resourceType.type, $scope);
|
||||||
|
|
||||||
|
// Local functions
|
||||||
|
|
||||||
|
function onLoad(response) {
|
||||||
|
ctrl.itemsSrc = response.data.items;
|
||||||
|
}
|
||||||
|
|
||||||
|
function actionResultHandler(returnValue) {
|
||||||
|
return $q.when(returnValue, actionSuccessHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
function actionSuccessHandler(result) { // eslint-disable-line no-unused-vars
|
||||||
|
|
||||||
|
// The action has completed (for whatever "complete" means to that
|
||||||
|
// action. Notice the view doesn't really need to know the semantics of the
|
||||||
|
// particular action because the actions return data in a standard form.
|
||||||
|
// That return includes the id and type of each created, updated, deleted
|
||||||
|
// and failed item.
|
||||||
|
//
|
||||||
|
// This handler is also careful to check the type of each item. This
|
||||||
|
// is important because actions which create non-items are launched from
|
||||||
|
// the items page (like create "volume" from image).
|
||||||
|
var deletedIds, updatedIds, createdIds, failedIds;
|
||||||
|
|
||||||
|
if ( result ) {
|
||||||
|
// Reduce the results to just item ids ignoring other types the action
|
||||||
|
// may have produced
|
||||||
|
deletedIds = actionResultService.getIdsOfType(result.deleted, ctrl.resourceType.type);
|
||||||
|
updatedIds = actionResultService.getIdsOfType(result.updated, ctrl.resourceType.type);
|
||||||
|
createdIds = actionResultService.getIdsOfType(result.created, ctrl.resourceType.type);
|
||||||
|
failedIds = actionResultService.getIdsOfType(result.failed, ctrl.resourceType.type);
|
||||||
|
|
||||||
|
// Handle deleted items
|
||||||
|
if (deletedIds.length) {
|
||||||
|
ctrl.itemsSrc = difference(ctrl.itemsSrc, deletedIds,'id');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle updated and created items
|
||||||
|
if ( updatedIds.length || createdIds.length ) {
|
||||||
|
// Ideally, get each created item individually, but
|
||||||
|
// this is simple and robust for the common use case.
|
||||||
|
// TODO: If we want more detailed updates, we could do so here.
|
||||||
|
ctrl.resourceType.listFunction().then(onLoad);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle failed items
|
||||||
|
if (failedIds.length) {
|
||||||
|
// Do nothing for now. Please note, actions may (and probably
|
||||||
|
// should) provide toast messages when something goes wrong.
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// promise resolved, but no result returned. Because the action didn't
|
||||||
|
// tell us what happened...reload the displayed items just in case.
|
||||||
|
ctrl.resourceType.listFunction().then(onLoad);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function difference(currentList, otherList, key) {
|
||||||
|
return currentList.filter(filter);
|
||||||
|
|
||||||
|
function filter(elem) {
|
||||||
|
return otherList.filter(function filterDeletedItem(deletedItem) {
|
||||||
|
return deletedItem === elem[key];
|
||||||
|
}).length === 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})();
|
@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* (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-generic-table controller', function() {
|
||||||
|
var ctrl, listFunctionDeferred, $timeout, actionResultDeferred;
|
||||||
|
|
||||||
|
beforeEach(module('horizon.framework.util'));
|
||||||
|
beforeEach(module('horizon.framework.conf'));
|
||||||
|
beforeEach(module('horizon.framework.widgets.table'));
|
||||||
|
|
||||||
|
var resourceType = {
|
||||||
|
type: 'OS::Test::Example',
|
||||||
|
getTableColumns: angular.noop,
|
||||||
|
listFunction: angular.noop,
|
||||||
|
globalActions: [],
|
||||||
|
batchActions: []
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(inject(function($controller, $q, _$timeout_) {
|
||||||
|
$timeout = _$timeout_;
|
||||||
|
var registry = {
|
||||||
|
getTypeNameBySlug: angular.noop,
|
||||||
|
getResourceType: angular.noop,
|
||||||
|
initActions: angular.noop
|
||||||
|
};
|
||||||
|
|
||||||
|
listFunctionDeferred = $q.defer();
|
||||||
|
actionResultDeferred = $q.defer();
|
||||||
|
spyOn(resourceType, 'listFunction').and.returnValue(listFunctionDeferred.promise);
|
||||||
|
spyOn(registry, 'getResourceType').and.returnValue(resourceType);
|
||||||
|
|
||||||
|
ctrl = $controller('horizon.framework.widgets.table.ResourceTableController', {
|
||||||
|
$scope: {},
|
||||||
|
'horizon.framework.conf.resource-type-registry.service': registry},
|
||||||
|
{resourceTypeName: 'OS::Test::Example'});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('exists', function() {
|
||||||
|
expect(ctrl).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets itemsSrc to the response data', function() {
|
||||||
|
listFunctionDeferred.resolve({data: {items: [1,2,3]}});
|
||||||
|
$timeout.flush();
|
||||||
|
expect(ctrl.itemsSrc).toEqual([1,2,3]);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('actionResultHandler', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
ctrl.itemsSrc = [{type: 'Something', id: -1}, {type: 'OS::Test::Example', id: 1}];
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles deleted items', function() {
|
||||||
|
actionResultDeferred.resolve({deleted: [{type: 'ignored', id: 0},
|
||||||
|
{type: 'OS::Test::Example', id: 1}]});
|
||||||
|
var promise = ctrl.actionResultHandler(actionResultDeferred.promise);
|
||||||
|
promise.then(function() {
|
||||||
|
expect(ctrl.itemsSrc).toEqual([{type: 'Something', id: -1}]);
|
||||||
|
});
|
||||||
|
$timeout.flush();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles updated items', function() {
|
||||||
|
actionResultDeferred.resolve({updated: [{type: 'OS::Test::Example', id: 1}]});
|
||||||
|
var promise = ctrl.actionResultHandler(actionResultDeferred.promise);
|
||||||
|
resourceType.listFunction.calls.reset();
|
||||||
|
promise.then(function() {
|
||||||
|
expect(resourceType.listFunction).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
$timeout.flush();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles created items', function() {
|
||||||
|
actionResultDeferred.resolve({created: [{type: 'OS::Test::Example', id: 1}]});
|
||||||
|
var promise = ctrl.actionResultHandler(actionResultDeferred.promise);
|
||||||
|
resourceType.listFunction.calls.reset();
|
||||||
|
promise.then(function() {
|
||||||
|
expect(resourceType.listFunction).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
$timeout.flush();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles failed items', function() {
|
||||||
|
actionResultDeferred.resolve({failed: [{type: 'OS::Test::Example', id: 1}]});
|
||||||
|
var promise = ctrl.actionResultHandler(actionResultDeferred.promise);
|
||||||
|
resourceType.listFunction.calls.reset();
|
||||||
|
promise.then(function() {
|
||||||
|
expect(resourceType.listFunction).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
$timeout.flush();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles falsy results', function() {
|
||||||
|
actionResultDeferred.resolve(false);
|
||||||
|
var promise = ctrl.actionResultHandler(actionResultDeferred.promise);
|
||||||
|
resourceType.listFunction.calls.reset();
|
||||||
|
promise.then(function() {
|
||||||
|
expect(resourceType.listFunction).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
$timeout.flush();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
})();
|
@ -0,0 +1,59 @@
|
|||||||
|
/**
|
||||||
|
* (c) Copyright 2016 Hewlett Packard Enterprise Development Company 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.framework.widgets.table')
|
||||||
|
.directive('hzResourceTable', directive);
|
||||||
|
|
||||||
|
directive.$inject = ['horizon.framework.widgets.basePath'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc directive
|
||||||
|
* @name hzResourceTable
|
||||||
|
* @description
|
||||||
|
* This directive produces a table and accompanying components that describe
|
||||||
|
* a list of resources of the given type. Based on information in the
|
||||||
|
* registry, the batch, global, and item-level actions are presented as
|
||||||
|
* appropriate. Search capabilities are also provided. The table contents
|
||||||
|
* are responsive to actions' promise resolutions, updating contents when
|
||||||
|
* they are likely to have changed. This directive allows for the rapid
|
||||||
|
* development of standard resource tables without having to rewrite
|
||||||
|
* boilerplate controllers, markup, etc.
|
||||||
|
* @example
|
||||||
|
```
|
||||||
|
<div>Here's some content above the table.</div>
|
||||||
|
<hz-resource-table resource-type-name="OS::Cinder::Volume"></hz-resource-table>
|
||||||
|
<div>Here's some content below the table.</div>
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
|
||||||
|
function directive(basePath) {
|
||||||
|
|
||||||
|
var directive = {
|
||||||
|
restrict: 'E',
|
||||||
|
scope: {
|
||||||
|
resourceTypeName: '@'
|
||||||
|
},
|
||||||
|
bindToController: true,
|
||||||
|
templateUrl: basePath + 'table/hz-resource-table.html',
|
||||||
|
controller: "horizon.framework.widgets.table.ResourceTableController as ctrl"
|
||||||
|
};
|
||||||
|
|
||||||
|
return directive;
|
||||||
|
}
|
||||||
|
})();
|
@ -0,0 +1,10 @@
|
|||||||
|
<hz-dynamic-table
|
||||||
|
table="ctrl"
|
||||||
|
config="ctrl.config"
|
||||||
|
items="ctrl.itemsSrc"
|
||||||
|
item-actions="ctrl.resourceType.itemActions"
|
||||||
|
client-full-text-search="true"
|
||||||
|
batch-actions="ctrl.batchActions"
|
||||||
|
filter-facets="ctrl.searchFacets"
|
||||||
|
result-handler="ctrl.actionResultHandler"
|
||||||
|
></hz-dynamic-table>
|
@ -26,6 +26,7 @@
|
|||||||
'horizon.framework.widgets.table',
|
'horizon.framework.widgets.table',
|
||||||
'horizon.framework.widgets.modal',
|
'horizon.framework.widgets.modal',
|
||||||
'horizon.framework.widgets.modal-wait-spinner',
|
'horizon.framework.widgets.modal-wait-spinner',
|
||||||
|
'horizon.framework.widgets.panel',
|
||||||
'horizon.framework.widgets.transfer-table',
|
'horizon.framework.widgets.transfer-table',
|
||||||
'horizon.framework.widgets.charts',
|
'horizon.framework.widgets.charts',
|
||||||
'horizon.framework.widgets.action-list',
|
'horizon.framework.widgets.action-list',
|
||||||
|
14
releasenotes/notes/resource-directives-44629f1116545141.yaml
Normal file
14
releasenotes/notes/resource-directives-44629f1116545141.yaml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
prelude: >
|
||||||
|
Angular components now exist to provide simple-to-
|
||||||
|
configure panels and tables, based off of registry
|
||||||
|
information about resources (e.g. Instances).
|
||||||
|
features:
|
||||||
|
- The hz-resource-table directive takes in a Heat
|
||||||
|
resource name (e.g. 'OS::Nova::Server') and uses
|
||||||
|
the Angular registry to provide actions, columns,
|
||||||
|
and summary views.
|
||||||
|
- The hz-resource-panel directive takes in a Heat
|
||||||
|
resource name (e.g. 'OS::Nova::Server') and
|
||||||
|
displays an appropriate header and allows content
|
||||||
|
to be transcluded to build the panel page.
|
Loading…
Reference in New Issue
Block a user