Applied scroll bar and infinite scrolling to host summary section. Added search field to task hosts and host summary sections.

This commit is contained in:
Chris Houseknecht 2014-05-01 00:14:36 -04:00
parent 468df5b7e3
commit 6b4b8ab6e3
6 changed files with 295 additions and 61 deletions

View File

@ -41,7 +41,9 @@ function Authenticate($cookieStore, $compile, $window, $scope, $rootScope, $loca
});
// Just in case, make sure the wait widget is not active
// and scroll the window to the top
Wait('stop');
window.scrollTo(0,0);
// Display the login dialog
$('#login-modal').modal({

View File

@ -10,7 +10,7 @@
'use strict';
function JobDetailController ($scope, $compile, $routeParams, ClearScope, Breadcrumbs, LoadBreadCrumbs, GetBasePath, Wait, Rest, ProcessErrors, DigestEvents,
SelectPlay, SelectTask, Socket, GetElapsed) {
SelectPlay, SelectTask, Socket, GetElapsed, SelectHost) {
ClearScope();
@ -27,6 +27,9 @@ function JobDetailController ($scope, $compile, $routeParams, ClearScope, Breadc
scope.hostResults = [];
scope.job_status = {};
scope.job_id = job_id;
scope.auto_scroll = false;
scope.searchTaskHostsEnabled = true;
scope.searchSummaryHostsEnabled = true;
event_socket = Socket({
scope: scope,
@ -272,39 +275,42 @@ function JobDetailController ($scope, $compile, $routeParams, ClearScope, Breadc
$scope.HostDetailOnTotalScroll = function(mcs) {
var url = GetBasePath('jobs') + job_id + '/job_events/?parent=' + scope.activeTask;
url += '&host__name__gt=' + scope.hostResults[scope.hostResults.length - 1].name + '&host__isnull=false&page_size=5&order_by=host__name';
Wait('start');
Rest.setUrl(url);
Rest.get()
.success(function(data) {
setTimeout(function() {
scope.$apply(function() {
data.results.forEach(function(row) {
scope.hostResults.push({
id: row.id,
status: ( (row.failed) ? 'failed': (row.changed) ? 'changed' : 'successful' ),
host_id: row.host,
task_id: row.parent,
name: row.event_data.host,
created: row.created,
msg: ( (row.event_data && row.event_data.res) ? row.event_data.res.msg : '' )
if (!scope.auto_scroll) {
Wait('start');
Rest.setUrl(url);
Rest.get()
.success(function(data) {
setTimeout(function() {
scope.$apply(function() {
data.results.forEach(function(row) {
scope.hostResults.push({
id: row.id,
status: ( (row.failed) ? 'failed': (row.changed) ? 'changed' : 'successful' ),
host_id: row.host,
task_id: row.parent,
name: row.event_data.host,
created: row.created,
msg: ( (row.event_data && row.event_data.res) ? row.event_data.res.msg : '' )
});
if (scope.hostResults.length > 10) {
scope.hostResults.splice(0,1);
}
});
if (scope.hostResults.length > 10) {
scope.hostResults.splice(0,1);
//$('#hosts-table-detail').mCustomScrollbar("update");
if (data.next) {
// there are more rows. move dragger up, letting user know.
setTimeout(function() { $('#hosts-table-detail .mCSB_dragger').css({ top: (mcs.draggerTop - 10) + 'px'}); }, 700);
}
});
$('#tasks-table-detail').mCustomScrollbar("update");
if (data.next) {
// there are more rows. move dragger up, letting user know.
setTimeout(function() { $('.mCSB_dragger').css({ top: (mcs.draggerTop - 10) + 'px'}); }, 700);
}
});
}, 100);
Wait('stop');
})
.error(function(data, status) {
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
msg: 'Call to ' + url + '. GET returned: ' + status });
});
}, 100);
Wait('stop');
})
.error(function(data, status) {
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
msg: 'Call to ' + url + '. GET returned: ' + status });
});
}
scope.auto_scroll = false;
};
$scope.HostDetailOnTotalScrollBack = function(mcs) {
@ -330,10 +336,10 @@ function JobDetailController ($scope, $compile, $routeParams, ClearScope, Breadc
scope.hostResults.pop();
}
});
$('#tasks-table-detail').mCustomScrollbar("update");
//$('#hosts-table-detail').mCustomScrollbar("update");
if (data.next) {
// there are more rows. move dragger down, letting user know.
setTimeout(function() { $('.mCSB_dragger').css({ top: (mcs.draggerTop + 10) + 'px' }); }, 700);
setTimeout(function() { $('#hosts-table-detail .mCSB_dragger').css({ top: (mcs.draggerTop + 10) + 'px' }); }, 700);
}
});
}, 100);
@ -344,8 +350,170 @@ function JobDetailController ($scope, $compile, $routeParams, ClearScope, Breadc
msg: 'Call to ' + url + '. GET returned: ' + status });
});
};
$scope.HostSummaryOnTotalScroll = function(mcs) {
var url = GetBasePath('jobs') + job_id + '/job_host_summaries/';
url += '?host__name__gt=' + scope.hosts[scope.hosts.length - 1].name + '&page_size=5&order_by=host__name';
if (!scope.auto_scroll) {
Wait('start');
Rest.setUrl(url);
Rest.get()
.success(function(data) {
setTimeout(function() {
scope.$apply(function() {
data.results.forEach(function(row) {
scope.hosts.push({
id: row.host,
name: row.summary_fields.host.name,
ok: row.ok,
changed: row.changed,
unreachable: row.dark,
failed: row.failures
});
if (scope.hosts.length > 10) {
scope.hosts.splice(0,1);
}
});
//$('#hosts-summary-table').mCustomScrollbar("update");
if (data.next) {
// there are more rows. move dragger up, letting user know.
setTimeout(function() { $('#hosts-summary-table .mCSB_dragger').css({ top: (mcs.draggerTop - 10) + 'px'}); }, 700);
}
});
}, 100);
Wait('stop');
})
.error(function(data, status) {
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
msg: 'Call to ' + url + '. GET returned: ' + status });
});
}
};
$scope.HostSummaryOnTotalScrollBack = function(mcs) {
var url = GetBasePath('jobs') + job_id + '/job_host_summaries/';
Wait('start');
url += '?host__name__lt=' + scope.hosts[0].name + '&page_size=5&order_by=-host__name';
Rest.setUrl(url);
Rest.get()
.success(function(data) {
setTimeout(function() {
scope.$apply(function() {
data.results.forEach(function(row) {
scope.hosts.unshift({
id: row.host,
name: row.summary_fields.host.name,
ok: row.ok,
changed: row.changed,
unreachable: row.dark,
failed: row.failures
});
if (scope.hosts.length > 10) {
scope.hosts.pop();
}
});
$('#hosts-summary-table').mCustomScrollbar("update");
if (data.next) {
// there are more rows. move dragger down, letting user know.
setTimeout(function() { $('#hosts-summary-table .mCSB_dragger').css({ top: (mcs.draggerTop + 10) + 'px' }); }, 700);
}
});
}, 100);
Wait('stop');
})
.error(function(data, status) {
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
msg: 'Call to ' + url + '. GET returned: ' + status });
});
};
$scope.searchTaskHosts = function() {
var url;
Wait('start');
scope.hostResults = [];
url = GetBasePath('jobs') + $routeParams.id + '/job_events/?parent=' + scope.activeTask;
url += (scope.task_host_name) ? '&host__name__icontains=' + scope.task_host_name : '';
url += '&host__name__isnull=false&page_size=10&order_by=host__name';
Rest.setUrl(url);
Rest.get()
.success(function(data) {
var i;
for (i = 0; i < data.results.length; i++) {
scope.hostResults.push({
id: data.results[i].id,
status: ( (data.results[i].failed) ? 'failed' : (data.results[i].changed) ? 'changed' : 'successful' ),
host_id: data.results[i].host,
task_id: data.results[i].parent,
name: data.results[i].summary_fields.host.name,
created: data.results[i].created,
msg: data.results[i].event_data.res.msg
});
}
Wait('stop');
SelectHost({ scope: scope });
})
.error(function(data, status) {
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
msg: 'Call to ' + url + '. GET returned: ' + status });
});
if (scope.task_host_name) {
scope.searchTaskHostsEnabled = false;
}
else {
scope.searchTaskHostsEnabled = true;
}
};
$scope.taskHostNameKeyPress = function(e) {
if (e.keyCode === 13) {
$scope.searchTaskHosts();
}
};
$scope.searchSummaryHosts = function() {
var url;
Wait('start');
scope.hosts = [];
url = GetBasePath('jobs') + $routeParams.id + '/job_host_summaries/?';
url += (scope.summary_host_name) ? 'host__name__icontains=' + scope.summary_host_name + '&': '';
url += 'page_size=10&order_by=host__name';
Rest.setUrl(url);
Rest.get()
.success(function(data) {
data.results.forEach(function(row) {
scope.hosts.push({
id: row.host,
name: row.summary_fields.host.name,
ok: row.ok,
changed: row.changed,
unreachable: row.dark,
failed: row.failures
});
});
Wait('stop');
$('#hosts-summary-table').mCustomScrollbar("update");
scope.auto_scroll = true;
setTimeout( function() { $('#hosts-summary-table').mCustomScrollbar("scrollTo", "bottom"); }, 700);
})
.error(function(data, status) {
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
msg: 'Call to ' + url + '. GET returned: ' + status });
});
if (scope.summary_host_name) {
scope.searchSummaryHostsEnabled = false;
}
else {
scope.searchSummaryHostsEnabled = true;
}
};
$scope.summaryHostNameKeyPress = function(e) {
if (e.keyCode === 13) {
$scope.searchSummaryHosts();
}
};
}
JobDetailController.$inject = [ '$scope', '$compile', '$routeParams', 'ClearScope', 'Breadcrumbs', 'LoadBreadCrumbs', 'GetBasePath', 'Wait',
'Rest', 'ProcessErrors', 'DigestEvents', 'SelectPlay', 'SelectTask', 'Socket', 'GetElapsed'
'Rest', 'ProcessErrors', 'DigestEvents', 'SelectPlay', 'SelectTask', 'Socket', 'GetElapsed', 'SelectHost'
];

View File

@ -474,23 +474,33 @@ function(UpdatePlayStatus, UpdatePlayNoHostsMatched, UpdateHostStatus, UpdatePla
});
if (!host_found) {
scope.hosts.push({
id: host_id,
name: name,
ok: (status === 'successful') ? 1 : 0,
changed: (status === 'changed') ? 1 : 0,
unreachable: (status === 'unreachable') ? 1 : 0,
failed: (status === 'failed') ? 1 : 0
});
scope.hosts.sort(function(a,b) {
if (a.name < b.name) {
return -1;
if (scope.hosts.length < 10 || name > scope.hosts[0].name) {
// This is a new host we want added to the list
scope.hosts.push({
id: host_id,
name: name,
ok: (status === 'successful') ? 1 : 0,
changed: (status === 'changed') ? 1 : 0,
unreachable: (status === 'unreachable') ? 1 : 0,
failed: (status === 'failed') ? 1 : 0
});
scope.hosts.sort(function(a,b) {
if (a.name < b.name) {
return -1;
}
if (a.name > b.name) {
return 1;
}
return 0;
});
// Only keep 10 hosts
if (scope.hosts.length > 10) {
scope.hosts.splice(0,1);
}
if (a.name > b.name) {
return 1;
}
return 0;
});
scope.auto_scroll = true;
$('#tasks-table-detail').mCustomScrollbar("update");
setTimeout( function() { $('#hosts-summary-table').mCustomScrollbar("scrollTo", "bottom"); }, 700);
}
}
UpdateTaskStatus({
@ -697,7 +707,7 @@ function(UpdatePlayStatus, UpdatePlayNoHostsMatched, UpdateHostStatus, UpdatePla
});
}
Wait('stop');
SelectHost();
SelectHost({ scope: scope });
})
.error(function(data, status) {
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
@ -707,11 +717,12 @@ function(UpdatePlayStatus, UpdatePlayNoHostsMatched, UpdateHostStatus, UpdatePla
}])
.factory('SelectHost', [ function() {
return function() {
return function(params) {
var scope = params.scope;
scope.auto_scroll = true;
setTimeout(function() {
var inner_height = $('#hosts-table-detail').innerHeight();
$('#hosts-table-detail').scrollTop(inner_height);
$('#tasks-table-detail').mCustomScrollbar("update");
setTimeout( function() { $('#hosts-table-detail').mCustomScrollbar("scrollTo", "bottom"); }, 700);
}, 100);
};
}]);

View File

@ -194,6 +194,36 @@
}
}
.header {
width: 100%;
height: 28px;
padding: bottom: 5px;
.title {
display: inline-block;
font-size: 14px;
font-weight: 500;
}
.search-field {
display: inline-block;
position: relative;
float: right;
input {
width: 250px;
}
a {
position: absolute;
right: 3px;
top: 3px;
color: #a9a9a9;
}
a:hover {
color: @black;
}
}
}
#task-hosts-section {
position: relative;
top: 0;

View File

@ -735,9 +735,7 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
scrollInertia: 0,
callbacks: {
onTotalScroll: scope[attrs.onTotalScroll],
//onTotalScrollOffset: 21,
onTotalScrollBack: scope[attrs.onTotalScrollBack],
//onTotalScrollBackOffset: 21
}
});
};

View File

@ -48,7 +48,7 @@
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-12">Name</div>
</div>
</div>
<div id="plays-table-detail" class="table-detail">
<div id="plays-table-detail" aw-custom-scroll class="table-detail">
<div class="row cursor-pointer" ng-repeat="play in plays" ng-class="play.playActiveClass" ng-click="selectPlay(play.id)">
<div class="col-lg-1 col-md-1 col-sm-2 hidden-xs">{{ play.created | date: 'HH:mm:ss' }}</div>
<div class="col-lg-1 col-md-1 hidden-sm hidden-xs" aw-tool-tip="Completed at {{ play.finished | date:'HH:mm:ss' }}"
@ -71,7 +71,7 @@
<div class="col-lg-5 col-md-5 hidden-xs hidden-sm">Host Status</div>
</div>
</div>
<div id="tasks-table-detail" class="table-detail">
<div id="tasks-table-detail" aw-custom-scroll class="table-detail">
<div class="row cursor-pointer" ng-repeat="task in tasks | filter:{ play_id: activePlay }" ng-class="task.taskActiveClass"
ng-click="selectTask(task.id)">
<div class="col-lg-1 col-md-1 col-sm-2 hidden-xs">{{ task.created | date: 'HH:mm:ss' }}</div>
@ -94,7 +94,14 @@
</div><!-- section -->
<div id="task-hosts-section" class="section">
<h5>Hosts</h5>
<div class="header">
<div class="title">Hosts</div>
<div class="search-field">
<input type="text" ng-model="task_host_name" placeholder="Search" ng-keypress="taskHostNameKeyPress($event)" />
<a class="search-icon" ng-show="searchTaskHostsEnabled" ng-click="searchTaskHosts()"><i class="fa fa-search"></i></a>
<a class="search-icon" ng-show="!searchTaskHostsEnabled" ng-click="task_host_name=''; searchTaskHosts()"><i class="fa fa-times"></i></a>
</div>
</div>
<div id="hosts-table-detail" aw-custom-scroll data-on-total-scroll="HostDetailOnTotalScroll"
data-on-total-scroll-back="HostDetailOnTotalScrollBack" class="table-detail">
<div id="hosts-table-detail-inner">
@ -106,6 +113,11 @@
{{ result.msg }}
</div>
</div>
<div class="row" ng-show="hostResults.length === 0">
<div class="col-lg-12">
<div class="loading-info">No records matched your search.</div>
</div>
</div>
</div>
</div>
</div><!-- section -->
@ -119,7 +131,14 @@
<div id="job-summary-container">
<div class="job_well">
<div id="hosts-summary-section" class="section job_summary">
<h5>Host Summary</h5>
<div class="header">
<div class="title">Host Summary</div>
<div class="search-field">
<input type="text" ng-model="summary_host_name" placeholder="Search" ng-keypress="summaryHostNameKeyPress($event)" />
<a class="search-icon" ng-show="searchSummaryHostsEnabled" ng-click="searchSummaryHosts()"><i class="fa fa-search"></i></a>
<a class="search-icon" ng-show="!searchSummaryHostsEnabled" ng-click="summary_host_name=''; searchSummaryHosts()"><i class="fa fa-times"></i></a>
</div>
</div>
<div class="table-header">
<div class="row">
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-4">Host</div>
@ -129,7 +148,8 @@
<div class="col-lg-2 col-md-2 col-sm-2 col-xs-2">Fail</div>
</div>
</div>
<div class="table-detail">
<div id="hosts-summary-table" class="table-detail" aw-custom-scroll data-on-total-scroll="HostSummaryOnTotalScroll"
data-on-total-scroll-back="HostSummaryOnTotalScrollBack">
<div class="row" ng-repeat="host in hosts" id="{{ host.id }}">
<div class="name col-lg-4 col-md-4 col-sm-4 col-xs-4"><a href="/#/home/hosts/?id={{ host.id }}"
aw-tool-tip="View host" data-placement="top">{{ host.name }}</a></div>
@ -138,6 +158,11 @@
<div class="col-lg-2 col-md-2 col-sm-2 col-xs-2">{{ host.unreachable }}</div>
<div class="col-lg-2 col-md-2 col-sm-2 col-xs-2">{{ host.failed }}</div>
</div>
<div class="row" ng-show="hosts.length === 0">
<div class="col-lg-12">
<div class="loading-info">No records matched your search.</div>
</div>
</div>
</div>
</div><!-- section -->
</div>