Merge "hz-resource-table handles transitional states"

This commit is contained in:
Jenkins 2016-08-08 20:28:25 +00:00 committed by Gerrit Code Review
commit 5dbbc329ca
10 changed files with 207 additions and 16 deletions

View File

@ -110,6 +110,8 @@
self.list = defaultListFunction;
self.setListFunction = setListFunction;
self.isListFunctionSet = isListFunctionSet;
self.itemInTransitionFunction = defaultItemInTransitionFunction;
self.setItemInTransitionFunction = setItemInTransitionFunction;
self.itemName = itemName;
self.setItemNameFunction = setItemNameFunction;
self.setPathParser = setPathParser;
@ -251,6 +253,40 @@
return Promise.reject({data: {items: []}});
}
/**
* @ngdoc function
* @name defaultItemInTransitionFunction
* @description
* A default implementation for the "itemInTransitionFunction function-pointer" which
* returns false every time.
* @returns {boolean}
*/
function defaultItemInTransitionFunction() {
return false;
}
/**
* Set a function that detects if an instance of this resource type is in a
* "transition" state, such as an image with a "queued" status, or an instance
* with an "in-progress" status. For example, this might be used to highlight
* a particular item in a list, or to set a progress indicator when viewing that
* items details.
*
* By default, a call to itemInTransitionFunction(item) will return false unless this
* function is registered for the resource type;
*
* @ngdoc function
* @param func - The callback-function to be used for determining if this
* resource is in a transitional state. This callback-function will be passed
* an object that is an instance of this resource (e.g. an image) and should
* return a boolean. "true" indicates the item is in a "transition" state.
* @returns {ResourceType} - returning self to facilitate call-chaining.
*/
function setItemInTransitionFunction(func) {
self.itemInTransitionFunction = func;
return self;
}
/**
* @ngdoc function
* @name getTableColumns

View File

@ -195,6 +195,18 @@
expect(type.list()).toBe('this would be a promise');
});
it("has a default isInTransition function that returns false", function() {
expect(type.itemInTransitionFunction()).toBe(false);
});
it("allows setting an isInTransition function", function() {
function isInTransitionTest() {
return "would return a boolean";
}
type.setItemInTransitionFunction(isInTransitionTest);
expect(type.itemInTransitionFunction()).toBe("would return a boolean");
});
it("allows setting of a summary template URL", function() {
type.setSummaryTemplateUrl('/my/path.html');
expect(type.summaryTemplateUrl).toBe('/my/path.html');

View File

@ -44,6 +44,10 @@
* It should ideally be used within the context of the `hz-dynamic-table` directive.
* 'table' can be referenced in a template if you want to pass in an outside scope.
*
* If the column has a itemInTransitionFunction property, that function will be
* called with the row's item. If the function returns true, a progress bar will
* be included in the cell.
*
* @restrict E
*
* @scope
@ -64,7 +68,8 @@
* 'a': 'apple',
* 'j': 'jacks'
* }
* }
* },
* {id: 'f', title: 'Status', itemInTransitionFunction: myInTransitionFunc},
* ]
* };
*
@ -98,13 +103,24 @@
function link(scope, element) {
var column = scope.column;
var html;
var progressBarHtml = '';
if (column && column.template) {
// if template provided, render, and place into cell
html = $compile(column.template)(scope);
} else {
// NOTE: 'table' is not passed to hz-field as hz-field is intentionally
// not cognizant of a 'table' context as hz-cell is.
html = $compile('<hz-field config="column" item="item"></hz-field>')(scope);
if (column.itemInTransitionFunction && column.itemInTransitionFunction(scope.item)) {
// NOTE(woodnt): It'd be nice to split this out into a template file,
// but since we're inside a link function, that's complicated.
progressBarHtml = '<div class="progress-text horizon-loading-bar">' +
'<div class="progress progress-striped active">' +
'<div class="progress-bar"></div>' +
'</div>' +
'</div>';
}
html = $compile(progressBarHtml +
'<hz-field config="column" item="item"></hz-field>')(scope);
}
element.append(html);
}

View File

@ -39,6 +39,9 @@
* searching. Filter will not be shown if this is not supplied (optional)
* @param {function=} resultHandler function that is called with return value
* from a clicked actions perform function passed into `actions` directive (optional)
* @param {function=} itemInTransitionFunction function that is called with each item in
* the table. If it returns true, the row is given the class "status_unknown" which by
* default highlights the row with a warning color.
*
* @description
* The `hzDynamicTable` directive generates all the HTML content for a table.
@ -121,7 +124,8 @@
batchActions: '=?',
itemActions: '=?',
filterFacets: '=?',
resultHandler: '=?'
resultHandler: '=?',
itemInTransitionFunction: '=?'
},
controller: 'horizon.framework.widgets.table.HzDynamicTableController',
templateUrl: basePath + 'table/hz-dynamic-table.html'

View File

@ -0,0 +1,82 @@
/*
* (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-dynamic-table directive', function() {
var $compile, $rootScope, $scope;
beforeEach(module('templates'));
beforeEach(module('smart-table'));
beforeEach(module('horizon.framework'));
beforeEach(module('horizon.framework.util'));
beforeEach(module('horizon.framework.conf'));
beforeEach(module('horizon.framework.widgets'));
beforeEach(module('horizon.framework.widgets.magic-search'));
beforeEach(module('horizon.framework.widgets.table'));
beforeEach(inject(function(_$compile_, _$rootScope_) {
$compile = _$compile_;
$rootScope = _$rootScope_;
$scope = $rootScope.$new();
}));
it("sets class when item in transition", function() {
var config = {
selectAll: false,
expand: false,
trackId: 'id',
columns: [
{id: 'a', title: 'A', priority: 1},
{id: 'b', title: 'B', priority: 2}
]
};
$scope.config = config;
$scope.tableConfig = config;
$scope.items = [
{
id: 1,
a: "a",
b: "b"
},
{
id: 2,
a: "a",
b: "b"
},
{
id: 3,
a: "a",
b: "b"
}
];
$scope.itemInTransitionFunc = function(item) {
return item.id === 1;
};
var element = $compile(
"<hz-dynamic-table" +
" config='tableConfig'" +
" items='items'" +
" item-in-transition-function='itemInTransitionFunc'>" +
"</hz-dynamic-table>")($scope);
$scope.$digest();
// 3 items in table, only one with ID that will return true from itemInTransitionFunc
expect(element.find("tr.status_unknown").length).toBe(1);
});
});
})();

View File

@ -52,7 +52,8 @@
classes rsp-p1 rsp-p2 are responsive priority as user resizes window.
-->
<tr ng-repeat-start="item in items track by item[config.trackId]"
ng-class="{'st-selected': checked[item[config.trackId]]}">
ng-class="{'st-selected': checked[item[config.trackId]],
'status_unknown': itemInTransitionFunction(item)}">
<td ng-show="config.selectAll" class="multi_select_column">
<div class="themable-checkbox">

View File

@ -40,6 +40,7 @@
ctrl.batchActions = [];
ctrl.items = [];
ctrl.itemsSrc = [];
ctrl.itemInTransitionFunction = itemInTransitionFunction;
// Watch for changes to search bar
$scope.$on(events.SERVER_SEARCH_UPDATED, handleServerSearch);
@ -187,6 +188,10 @@
}).length === 0;
}
}
function itemInTransitionFunction(item) {
return ctrl.resourceType.itemInTransitionFunction(item);
}
}
})();

View File

@ -31,7 +31,8 @@
getTableColumns: angular.noop,
list: angular.noop,
globalActions: [],
batchActions: []
batchActions: [],
itemInTransitionFunction: angular.noop
};
beforeEach(inject(function($rootScope, $controller, $q) {
@ -207,6 +208,14 @@
});
});
describe('item in transition function', function() {
it('it calls resource type itemInTransitionFunction', function() {
spyOn(resourceType, "itemInTransitionFunction");
ctrl.itemInTransitionFunction();
expect(resourceType.itemInTransitionFunction.calls.count()).toBe(1);
});
});
});
})();

View File

@ -7,4 +7,5 @@
batch-actions="ctrl.batchActions"
filter-facets="ctrl.searchFacets"
result-handler="ctrl.actionResultHandler"
item-in-transition-function="ctrl.itemInTransitionFunction"
></hz-dynamic-table>

View File

@ -87,8 +87,11 @@ $em-per-priority: floor($table-col-avg-width / $font-size-base) * 3;
opacity: 0;
}
&:not(.st-sort-ascent):hover:after, &:not(.st-sort-descent):hover:after {
opacity: 1;
&:not(.st-sort-ascent),
&:not(.st-sort-descent) {
&:hover:after {
opacity: 1;
}
}
}
@ -149,30 +152,52 @@ $em-per-priority: floor($table-col-avg-width / $font-size-base) * 3;
&.table-striped {
tbody {
tr {
&:nth-child(2n+1) > td, &:nth-child(2n+1) + .detail-row > td {
background-color: $table-bg-accent;
&:nth-child(2n+1) {
> td,
+ .detail-row > td {
background-color: $table-bg-accent;
}
&.status_unknown td {
background-color: lighten($brand-warning, 10%);
}
}
&,
&.spacer-row > td, &.spacer-row:nth-child(6n+3) + tr + tr.detail-row td,
&.detail-row:nth-child(4n+2) + tr:not(.spacer-row) td,
&.detail-row:nth-child(4n+2) + tr:not(.spacer-row) + tr.detail-row td {
&.spacer-row > td,
&.spacer-row:nth-child(6n+3) + tr + tr.detail-row td {
background-color: transparent;
}
&.detail-row:nth-child(4n+2) + tr:not(.spacer-row) {
td,
+ tr.detail-row td {
background-color: transparent;
}
&.status_unknown td {
background-color: lighten($brand-warning, 6%);
}
}
}
}
}
}
@media only all {
.rsp-p1, .rsp-p2,
.rsp-p3, .rsp-p4 {
.rsp-p1,
.rsp-p2,
.rsp-p3,
.rsp-p4 {
display: none;
}
th,td {
&.rsp-alt-p1, &.rsp-alt-p2,
&.rsp-alt-p3, &.rsp-alt-p4 {
&.rsp-alt-p1,
&.rsp-alt-p2,
&.rsp-alt-p3,
&.rsp-alt-p4 {
display: inline-block;
}
}