Skip to content

Commit df5af8b

Browse files
Merge pull request #330 from dgutride/expanding-listview
Add list view expansion to Angular-Patternfly
2 parents 9967db2 + 6d506db commit df5af8b

File tree

6 files changed

+140
-43
lines changed

6 files changed

+140
-43
lines changed

misc/examples.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ hr {
6464
padding-left: 5px;
6565
}
6666

67+
.list-view-container .fa {
68+
padding-left: 0px;
69+
}
70+
6771
.card-view-container {
6872
border: 1px solid #000000;
6973
margin: 10px;

src/views/listview/list-view-directive.js

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
* Pass a customScope object containing any scope variables/functions you need to access from the transcluded source, access these
88
* via 'customScope' in your transcluded hmtl.
99
* <br><br>
10+
* If using expanding rows, use a list-expanded-content element containing expandable content for each row. For each item in the items array, the expansion can be disabled by setting disableRowExpansion to true on the item.
1011
*
1112
* @param {array} items Array of items to display in the list view. If an item in the array has a 'rowClass' field, the value of this field will be used as a class specified on the row (list-group-item).
1213
* @param {object} config Configuration settings for the list view:
@@ -15,6 +16,7 @@
1516
* <li>.selectItems - (boolean) Allow row selection, default is false
1617
* <li>.dlbClick - (boolean) Handle double clicking (item remains selected on a double click). Default is false.
1718
* <li>.multiSelect - (boolean) Allow multiple row selections, selectItems must also be set, not applicable when dblClick is true. Default is false
19+
* <li>.useExpandingRows - (boolean) Allow row expansion for each list item.
1820
* <li>.selectionMatchProp - (string) Property of the items to use for determining matching, default is 'uuid'
1921
* <li>.selectedItems - (array) Current set of selected items
2022
* <li>.checkDisabled - ( function(item) ) Function to call to determine if an item is disabled, default is none
@@ -76,6 +78,36 @@
7678
{{item.state}}
7779
</div>
7880
</div>
81+
<list-expanded-content>
82+
{{item.city}}
83+
<div class="row">
84+
<div class="col-md-3">
85+
<div pf-donut-pct-chart config="exampleChartConfig" data="{'used': '350','total': '1000'}" center-label="'Percent Used'"></div>
86+
</div>
87+
<div class="col-md-9">
88+
<dl class="dl-horizontal">
89+
<dt>Host Name</dt>
90+
<dd>Hostceph1</dd>
91+
<dt>Device Path</dt>
92+
<dd>/dev/disk/pci-0000.05:00-sas-0.2-part1</dd>
93+
<dt>Time</dt>
94+
<dd>January 15, 2016 10:45:11 AM</dd>
95+
<dt>Severity</dt>
96+
<dd>Warning</dd>
97+
<dt>Cluster</dt>
98+
<dd>Cluster 1</dd>
99+
</dl>
100+
<p>
101+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
102+
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
103+
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
104+
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
105+
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
106+
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
107+
</p>
108+
</div>
109+
</div>
110+
</list-expanded-content>
79111
</div>
80112
</div>
81113
<hr class="col-md-12">
@@ -114,6 +146,9 @@
114146
<label class="checkbox-inline">
115147
<input type="checkbox" ng-model="showDisabled">Show Disabled Rows</input>
116148
</label>
149+
<label class="checkbox-inline">
150+
<input type="checkbox" ng-model="config.useExpandingRows">Show Expanding Rows</input>
151+
</label>
117152
</div>
118153
</form>
119154
</div>
@@ -161,6 +196,15 @@
161196
}
162197
};
163198
199+
$scope.exampleChartConfig = {
200+
'chartId': 'pctChart',
201+
'units': 'GB',
202+
'thresholds': {
203+
'warning':'60',
204+
'error':'90'
205+
}
206+
};
207+
164208
$scope.selectType = 'checkbox';
165209
$scope.updateSelectionType = function() {
166210
if ($scope.selectType === 'checkbox') {
@@ -185,6 +229,7 @@
185229
selectedItems: [],
186230
checkDisabled: checkDisabledItem,
187231
showSelectBox: true,
232+
useExpandingRows: false,
188233
onSelect: handleSelect,
189234
onSelectionChange: handleSelectionChange,
190235
onCheckBoxChange: handleCheckBoxChange,
@@ -203,7 +248,8 @@
203248
name: "John Smith",
204249
address: "415 East Main Street",
205250
city: "Norfolk",
206-
state: "Virginia"
251+
state: "Virginia",
252+
disableRowExpansion: true
207253
},
208254
{
209255
name: "Frank Livingston",
@@ -353,7 +399,9 @@ angular.module('patternfly.views').directive('pfListView', function ($timeout, $
353399
updateActionForItemFn: '=?',
354400
customScope: '=?'
355401
},
356-
transclude: true,
402+
transclude: {
403+
expandedContent: '?listExpandedContent'
404+
},
357405
templateUrl: 'views/listview/list-view.html',
358406
controller:
359407
function ($scope, $element) {
@@ -380,6 +428,7 @@ angular.module('patternfly.views').directive('pfListView', function ($timeout, $
380428
selectionMatchProp: 'uuid',
381429
selectedItems: [],
382430
checkDisabled: false,
431+
useExpandingRows: false,
383432
showSelectBox: true,
384433
onSelect: null,
385434
onSelectionChange: null,
@@ -442,6 +491,10 @@ angular.module('patternfly.views').directive('pfListView', function ($timeout, $
442491
return hideMenu;
443492
};
444493

494+
$scope.toggleItemExpansion = function (item) {
495+
item.isExpanded = !item.isExpanded;
496+
};
497+
445498
$scope.setupActions = function (item, event) {
446499
// Ignore disabled items completely
447500
if ($scope.checkDisabled(item)) {

src/views/listview/list-view.html

Lines changed: 47 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,55 @@
1-
<div class="list-view-pf">
1+
<div class="list-group list-view-pf">
22
<div class="list-group-item {{item.rowClass}}"
33
ng-repeat="item in items track by $index"
4-
ng-class="{'pf-selectable': selectItems, 'active': isSelected(item), 'disabled': checkDisabled(item)}">
5-
<div class="list-view-pf-checkbox" ng-if="config.showSelectBox" >
6-
<input type="checkbox" value="item.selected" ng-model="item.selected" ng-disabled="checkDisabled(item)" ng-change="checkBoxChange(item)"/>
7-
</div>
4+
ng-class="{'pf-selectable': selectItems, 'active': isSelected(item), 'disabled': checkDisabled(item), 'list-view-pf-expand-active': item.isExpanded}">
5+
<div class="list-group-item-header">
6+
<div class="list-view-pf-expand" ng-if="config.useExpandingRows">
7+
<span class="fa fa-angle-right" ng-show="!item.disableRowExpansion" ng-click="toggleItemExpansion(item)" ng-class="{'fa-angle-down': item.isExpanded}"></span>
8+
<span class="pf-expand-placeholder" ng-show="item.disableRowExpansion"></span>
9+
</div>
10+
<div class="list-view-pf-checkbox" ng-if="config.showSelectBox" >
11+
<input type="checkbox" value="item.selected" ng-model="item.selected" ng-disabled="checkDisabled(item)" ng-change="checkBoxChange(item)"/>
12+
</div>
813

9-
<div class="list-view-pf-actions"
10-
ng-if="(actionButtons && actionButtons.length > 0) || (menuActions && menuActions.length > 0)">
11-
<button class="btn btn-default {{actionButton.class}}" ng-repeat="actionButton in actionButtons"
12-
title="{{actionButton.title}}"
13-
ng-class="{'disabled' : checkDisabled(item) || !enableButtonForItem(actionButton, item)}"
14-
ng-click="handleButtonAction(actionButton, item)">
15-
<div ng-if="actionButton.include" class="actionButton.includeClass" ng-include src="actionButton.include"></div>
16-
<span ng-if="!actionButton.include">{{actionButton.name}}</span>
17-
</button>
18-
<div class="{{dropdownClass}} pull-right dropdown-kebab-pf {{getMenuClassForItem(item)}} {{hideMenuForItem(item) ? 'invisible' : ''}}"
19-
id="kebab_{{$index}}"
20-
ng-if="menuActions && menuActions.length > 0">
21-
<button class="btn btn-link dropdown-toggle" type="button"
22-
id="dropdownKebabRight_{{$index}}"
23-
ng-class="{'disabled': checkDisabled(item)}"
24-
ng-click="setupActions(item, $event)"
25-
data-toggle="dropdown"
26-
aria-haspopup="true"
27-
aria-expanded="true">
28-
<span class="fa fa-ellipsis-v"></span>
14+
<div class="list-view-pf-actions"
15+
ng-if="(actionButtons && actionButtons.length > 0) || (menuActions && menuActions.length > 0)">
16+
<button class="btn btn-default {{actionButton.class}}" ng-repeat="actionButton in actionButtons"
17+
title="{{actionButton.title}}"
18+
ng-class="{'disabled' : checkDisabled(item) || !enableButtonForItem(actionButton, item)}"
19+
ng-click="handleButtonAction(actionButton, item)">
20+
<div ng-if="actionButton.include" class="actionButton.includeClass" ng-include src="actionButton.include"></div>
21+
<span ng-if="!actionButton.include">{{actionButton.name}}</span>
2922
</button>
30-
<ul class="dropdown-menu dropdown-menu-right {{$index}}" aria-labelledby="dropdownKebabRight_{{$index}}" >
31-
<li ng-repeat="menuAction in menuActions"
32-
ng-if="menuAction.isVisible !== false"
33-
role="{{menuAction.isSeparator === true ? 'separator' : 'menuitem'}}"
34-
ng-class="{'divider': (menuAction.isSeparator === true), 'disabled': (menuAction.isDisabled === true)}">
35-
<a ng-if="menuAction.isSeparator !== true" title="{{menuAction.title}}" ng-click="handleMenuAction(menuAction, item)">
36-
{{menuAction.name}}
37-
</a>
38-
</li>
39-
</ul>
23+
<div class="{{dropdownClass}} pull-right dropdown-kebab-pf {{getMenuClassForItem(item)}} {{hideMenuForItem(item) ? 'invisible' : ''}}"
24+
id="kebab_{{$index}}"
25+
ng-if="menuActions && menuActions.length > 0">
26+
<button class="btn btn-link dropdown-toggle" type="button"
27+
id="dropdownKebabRight_{{$index}}"
28+
ng-class="{'disabled': checkDisabled(item)}"
29+
ng-click="setupActions(item, $event)"
30+
data-toggle="dropdown"
31+
aria-haspopup="true"
32+
aria-expanded="true">
33+
<span class="fa fa-ellipsis-v"></span>
34+
</button>
35+
<ul class="dropdown-menu dropdown-menu-right {{$index}}" aria-labelledby="dropdownKebabRight_{{$index}}" >
36+
<li ng-repeat="menuAction in menuActions"
37+
ng-if="menuAction.isVisible !== false"
38+
role="{{menuAction.isSeparator === true ? 'separator' : 'menuitem'}}"
39+
ng-class="{'divider': (menuAction.isSeparator === true), 'disabled': (menuAction.isDisabled === true)}">
40+
<a ng-if="menuAction.isSeparator !== true" title="{{menuAction.title}}" ng-click="handleMenuAction(menuAction, item)">
41+
{{menuAction.name}}
42+
</a>
43+
</li>
44+
</ul>
45+
</div>
46+
</div>
47+
<div pf-transclude="parent"
48+
class="list-view-pf-main-info"
49+
ng-click="itemClick($event, item)"
50+
ng-dblclick="dblClick($event, item)">
4051
</div>
4152
</div>
42-
<div pf-transclude="parent"
43-
class="list-view-pf-main-info"
44-
ng-click="itemClick($event, item)"
45-
ng-dblclick="dblClick($event, item)">
46-
</div>
53+
<div class="list-group-item-container container-fluid" ng-transclude="expandedContent" ng-if="config.useExpandingRows && item.isExpanded"></div>
4754
</div>
4855
</div>

src/views/views.module.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55
* Views module for patternfly.
66
*
77
*/
8-
angular.module('patternfly.views', ['patternfly.utils', 'patternfly.filters', 'patternfly.sort']);
8+
angular.module('patternfly.views', ['patternfly.utils', 'patternfly.filters', 'patternfly.sort', 'patternfly.charts']);

styles/angular-patternfly.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,3 +460,7 @@ accordion > .panel-group .panel-open .panel-title > a:before {
460460
.wizard-pf-cancel-inline {
461461
margin-left: 25px;
462462
}
463+
464+
.pf-expand-placeholder {
465+
margin-right: 10px;
466+
}

test/views/listview/list-view.spec.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,4 +513,33 @@ describe('Directive: pfDataList', function () {
513513
var alteredKebab = element.find('.dropdown-kebab-pf.test-class');
514514
expect(alteredKebab.length).toBe(1);
515515
});
516+
517+
it('should allow expanding rows', function () {
518+
var items;
519+
$scope.listConfig.useExpandingRows = true;
520+
521+
$scope.$digest();
522+
523+
items = element.find('.list-view-pf-expand .fa-angle-right');
524+
expect(items.length).toBe(5);
525+
526+
eventFire(items[0], 'click');
527+
528+
var openItem = element.find('.list-group-item-container');
529+
expect(openItem.length).toBe(1);
530+
});
531+
532+
it('should allow expanding rows to disable individual expansion', function () {
533+
$scope.systemModel[0].disableRowExpansion = true;
534+
$scope.listConfig.useExpandingRows = true;
535+
var htmlTmp = '<div pf-list-view items="systemModel" ' +
536+
' config="listConfig">' +
537+
'</div>';
538+
539+
compileHTML(htmlTmp, $scope);
540+
541+
// Make sure one item is hiding the expansion action (based on the item settings above)
542+
items = element.find('.list-view-pf-expand .fa-angle-right.ng-hide');
543+
expect(items.length).toBe(1);
544+
});
516545
});

0 commit comments

Comments
 (0)