Better UX for build logs when switching focus back to tab
Currently, build logs are not loaded when the tab is in the background. However, when switching back to the tab, there is no indication that logs have not loaded, and it can take up to the poll duration (5s) before we even start loading the logs. This change adds a message displayed for the user before the logs start to load to indicate they are being refreshed and also *immediately* starts the loading of the logs when the tab is made visible. Fixes #501
This commit is contained in:
parent
0316f6e471
commit
4829ec51ca
3 changed files with 56 additions and 35 deletions
|
@ -24,34 +24,41 @@
|
|||
please check for JavaScript or networking issues and contact support.
|
||||
</div>
|
||||
|
||||
<span class="no-logs" ng-if="!logEntries.length && currentBuild.phase == 'waiting'">
|
||||
(Waiting for build to start)
|
||||
</span>
|
||||
<div ng-show="!loadError && pollChannel.skipping">
|
||||
Refreshing Build Status...
|
||||
<span class="cor-loader"></span>
|
||||
</div>
|
||||
|
||||
<div class="log-container" ng-class="container.type" ng-repeat="container in logEntries">
|
||||
<div class="container-header" ng-class="container.type == 'phase' ? container.message : ''"
|
||||
ng-switch on="container.type" ng-click="container.logs.toggle()">
|
||||
<i class="fa chevron"
|
||||
ng-class="container.logs.isVisible ? 'fa-chevron-down' : 'fa-chevron-right'"
|
||||
ng-show="hasLogs(container)"></i>
|
||||
<div ng-switch-when="phase">
|
||||
<span class="container-content build-log-phase" phase="container"></span>
|
||||
</div>
|
||||
<div ng-switch-when="error">
|
||||
<span class="container-content build-log-error" error="container" entries="logEntries"></span>
|
||||
</div>
|
||||
<div ng-switch-when="command">
|
||||
<span class="container-content build-log-command" command="container"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-show="!pollChannel.skipping">
|
||||
<span class="no-logs" ng-if="!logEntries.length && currentBuild.phase == 'waiting'">
|
||||
(Waiting for build to start)
|
||||
</span>
|
||||
|
||||
<!-- Display the entries for the container -->
|
||||
<div class="container-logs" ng-show="container.logs.isVisible">
|
||||
<div class="log-entry" bindonce ng-repeat="entry in container.logs.visibleEntries">
|
||||
<span class="id" bo-text="$index + container.index + 1" ng-if="!useTimestamps"></span>
|
||||
<span class="id" bo-text="formatDatetime(entry.data.datetime)" ng-if="useTimestamps"></span>
|
||||
<span class="message" bo-html="processANSI(entry.message, container)"></span>
|
||||
<span class="timestamp" bo-text="formatDatetime(entry.data.datetime)" ng-if="!useTimestamps"></span>
|
||||
<div class="log-container" ng-class="container.type" ng-repeat="container in logEntries">
|
||||
<div class="container-header" ng-class="container.type == 'phase' ? container.message : ''"
|
||||
ng-switch on="container.type" ng-click="container.logs.toggle()">
|
||||
<i class="fa chevron"
|
||||
ng-class="container.logs.isVisible ? 'fa-chevron-down' : 'fa-chevron-right'"
|
||||
ng-show="hasLogs(container)"></i>
|
||||
<div ng-switch-when="phase">
|
||||
<span class="container-content build-log-phase" phase="container"></span>
|
||||
</div>
|
||||
<div ng-switch-when="error">
|
||||
<span class="container-content build-log-error" error="container" entries="logEntries"></span>
|
||||
</div>
|
||||
<div ng-switch-when="command">
|
||||
<span class="container-content build-log-command" command="container"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Display the entries for the container -->
|
||||
<div class="container-logs" ng-show="container.logs.isVisible">
|
||||
<div class="log-entry" bindonce ng-repeat="entry in container.logs.visibleEntries">
|
||||
<span class="id" bo-text="$index + container.index + 1" ng-if="!useTimestamps"></span>
|
||||
<span class="id" bo-text="formatDatetime(entry.data.datetime)" ng-if="useTimestamps"></span>
|
||||
<span class="message" bo-html="processANSI(entry.message, container)"></span>
|
||||
<span class="timestamp" bo-text="formatDatetime(entry.data.datetime)" ng-if="!useTimestamps"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -28,7 +28,7 @@ angular.module('quay').directive('buildLogsView', function () {
|
|||
$scope.currentBuild = null;
|
||||
$scope.loadError = null;
|
||||
|
||||
var pollChannel = null;
|
||||
$scope.pollChannel = null;
|
||||
|
||||
var appendToTextLog = function(type, message) {
|
||||
if (type == 'phase') {
|
||||
|
@ -146,14 +146,14 @@ angular.module('quay').directive('buildLogsView', function () {
|
|||
getBuildStatusAndLogs(build, callback);
|
||||
};
|
||||
|
||||
pollChannel = AngularPollChannel.create($scope, conductStatusAndLogRequest, 5 * 1000 /* 5s */);
|
||||
pollChannel.start();
|
||||
$scope.pollChannel = AngularPollChannel.create($scope, conductStatusAndLogRequest, 5 * 1000 /* 5s */);
|
||||
$scope.pollChannel.start();
|
||||
};
|
||||
|
||||
var stopWatching = function() {
|
||||
if (pollChannel) {
|
||||
pollChannel.stop();
|
||||
pollChannel = null;
|
||||
if ($scope.pollChannel) {
|
||||
$scope.pollChannel.stop();
|
||||
$scope.pollChannel = null;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
20
static/js/services/angular-poll-channel.js
vendored
20
static/js/services/angular-poll-channel.js
vendored
|
@ -1,8 +1,9 @@
|
|||
/**
|
||||
* Specialized class for conducting an HTTP poll, while properly preventing multiple calls.
|
||||
*/
|
||||
angular.module('quay').factory('AngularPollChannel', ['ApiService', '$timeout', 'DocumentVisibilityService',
|
||||
function(ApiService, $timeout, DocumentVisibilityService) {
|
||||
angular.module('quay').factory('AngularPollChannel',
|
||||
['ApiService', '$timeout', 'DocumentVisibilityService', 'CORE_EVENT', '$rootScope',
|
||||
function(ApiService, $timeout, DocumentVisibilityService, CORE_EVENT, $rootScope) {
|
||||
var _PollChannel = function(scope, requester, opt_sleeptime) {
|
||||
this.scope_ = scope;
|
||||
this.requester_ = requester;
|
||||
|
@ -11,10 +12,20 @@ angular.module('quay').factory('AngularPollChannel', ['ApiService', '$timeout',
|
|||
|
||||
this.working = false;
|
||||
this.polling = false;
|
||||
this.skipping = false;
|
||||
|
||||
var that = this;
|
||||
|
||||
var visibilityHandler = $rootScope.$on(CORE_EVENT.DOC_VISIBILITY_CHANGE, function() {
|
||||
// If the poll channel was skipping because the visibility was hidden, call it immediately.
|
||||
if (that.skipping && !DocumentVisibilityService.isHidden()) {
|
||||
that.call_();
|
||||
}
|
||||
});
|
||||
|
||||
scope.$on('$destroy', function() {
|
||||
that.stop();
|
||||
visibilityHandler();
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -28,9 +39,10 @@ angular.module('quay').factory('AngularPollChannel', ['ApiService', '$timeout',
|
|||
if (this.timer_) {
|
||||
$timeout.cancel(this.timer_);
|
||||
this.timer_ = null;
|
||||
this.polling_ = false;
|
||||
this.polling = false;
|
||||
}
|
||||
|
||||
this.skipping = false;
|
||||
this.working = false;
|
||||
};
|
||||
|
||||
|
@ -53,6 +65,7 @@ angular.module('quay').factory('AngularPollChannel', ['ApiService', '$timeout',
|
|||
|
||||
// If the document is currently hidden, skip the call.
|
||||
if (DocumentVisibilityService.isHidden()) {
|
||||
this.skipping = true;
|
||||
this.setupTimer_();
|
||||
return;
|
||||
}
|
||||
|
@ -63,6 +76,7 @@ angular.module('quay').factory('AngularPollChannel', ['ApiService', '$timeout',
|
|||
that.requester_(function(status) {
|
||||
if (status) {
|
||||
that.working = false;
|
||||
that.skipping = false;
|
||||
that.setupTimer_();
|
||||
} else {
|
||||
that.stop();
|
||||
|
|
Reference in a new issue