diff --git a/static/css/quay.css b/static/css/quay.css index 70d2b1527..82830eecb 100644 --- a/static/css/quay.css +++ b/static/css/quay.css @@ -1749,69 +1749,113 @@ p.editable:hover i { overflow: auto; } - -.repo-build .build-pane .build-logs .command-logs { - margin: 10px; - padding-right: 10px; +.repo-build .build-pane .build-logs .container-header { + padding: 2px; } -.repo-build .build-pane .build-logs .command-entry, -.repo-build .build-pane .build-logs .log-entry { +.repo-build .build-pane .build-logs .container-logs { + margin: 4px; + padding-bottom: 4px; +} + +.repo-build .build-pane .build-logs .command-title, +.repo-build .build-pane .build-logs .log-entry .message { font-family: Consolas, "Lucida Console", Monaco, monospace; + font-size: 13px; } -.repo-build .build-pane .build-logs .command-entry { +.repo-build .build-pane .build-logs .container-header { cursor: pointer; position: relative; } -.repo-build .build-pane .build-logs .command-entry i.fa.chevron { +.repo-build .build-pane .build-logs .container-header i.fa.chevron { color: #666; margin-right: 4px; width: 14px; text-align: center; position: absolute; - top: 2px; + top: 6px; left: 0px; } -.repo-build .build-pane .build-logs .command-entry .label { - text-align: center; +.repo-build .build-pane .build-logs .log-container.command { + margin-left: 42px; +} + +.repo-build .build-pane .build-logs .container-header.building { + margin-bottom: 10px; +} + +.repo-build .build-pane .build-logs .container-header.pushing { + margin-top: 10px; +} + +.repo-build .build-log-error-element { + position: relative; + display: inline-block; + margin: 10px; + padding: 10px; + background: rgba(255, 0, 0, 0.17); + border-radius: 10px; + margin-left: 22px; +} + +.repo-build .build-log-error-element i.fa { + color: red; + position: absolute; + top: 13px; + left: 11px; +} + +.repo-build .build-log-error-element .error-message { + display: inline-block; + margin-left: 25px; +} + +.repo-build .build-pane .build-logs .container-header .label { + padding-top: 4px; + text-align: right; margin-right: 4px; - vertical-align: middle; width: 86px; display: inline-block; - background-color: #aaa; + + border-right: 4px solid #aaa; + background-color: #444; position: absolute; - top: 2px; + top: 4px; left: 24px; } -.repo-build .build-pane .build-logs .command-entry .command-title { +.repo-build .build-pane .build-logs .container-header .container-content { display: block; + padding-left: 20px; +} + +.repo-build .build-pane .build-logs .container-header .container-content.build-log-command { padding-left: 120px; } .label.FROM { - background-color: #5bc0de !important; + border-color: #5bc0de !important; } .label.CMD, .label.EXPOSE, .label.ENTRYPOINT { - background-color: #428bca !important; + border-color: #428bca !important; } .label.RUN, .label.ADD { - background-color: #5cb85c !important; + border-color: #5cb85c !important; } .label.ENV, .label.VOLUME, .label.USER, .label.WORKDIR { - background-color: #f0ad4e !important; + border-color: #f0ad4e !important; } .label.MAINTAINER { - background-color: #aaa !important; + border-color: #aaa !important; } .repo-build .build-pane .build-logs .log-entry { diff --git a/static/directives/build-log-command.html b/static/directives/build-log-command.html new file mode 100644 index 000000000..211667ee4 --- /dev/null +++ b/static/directives/build-log-command.html @@ -0,0 +1,6 @@ + + + + + diff --git a/static/directives/build-log-error.html b/static/directives/build-log-error.html new file mode 100644 index 000000000..095f8edd0 --- /dev/null +++ b/static/directives/build-log-error.html @@ -0,0 +1,4 @@ + + + + diff --git a/static/directives/build-log-phase.html b/static/directives/build-log-phase.html new file mode 100644 index 000000000..503593923 --- /dev/null +++ b/static/directives/build-log-phase.html @@ -0,0 +1,4 @@ + + + + diff --git a/static/directives/build-message.html b/static/directives/build-message.html index af3edd285..17895dd28 100644 --- a/static/directives/build-message.html +++ b/static/directives/build-message.html @@ -1 +1 @@ -{{ getBuildMessage(build) }} +{{ getBuildMessage(phase) }} diff --git a/static/directives/build-progress.html b/static/directives/build-progress.html index bc3dd0575..ac719d449 100644 --- a/static/directives/build-progress.html +++ b/static/directives/build-progress.html @@ -1,5 +1,5 @@
-
+
diff --git a/static/directives/build-status.html b/static/directives/build-status.html index 9b0226e80..cf5ded997 100644 --- a/static/directives/build-status.html +++ b/static/directives/build-status.html @@ -1,7 +1,7 @@
- +
diff --git a/static/js/app.js b/static/js/app.js index 69ee8e886..5fa2993d7 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -2476,6 +2476,119 @@ quayApp.directive('namespaceSelector', function () { }); +quayApp.directive('buildLogPhase', function () { + var directiveDefinitionObject = { + priority: 0, + templateUrl: '/static/directives/build-log-phase.html', + replace: false, + transclude: false, + restrict: 'C', + scope: { + 'phase': '=phase' + }, + controller: function($scope, $element) { + } + }; + return directiveDefinitionObject; +}); + + +quayApp.directive('buildLogError', function () { + var directiveDefinitionObject = { + priority: 0, + templateUrl: '/static/directives/build-log-error.html', + replace: false, + transclude: false, + restrict: 'C', + scope: { + 'error': '=error' + }, + controller: function($scope, $element) { + } + }; + return directiveDefinitionObject; +}); + + +quayApp.directive('buildLogCommand', function () { + var directiveDefinitionObject = { + priority: 0, + templateUrl: '/static/directives/build-log-command.html', + replace: false, + transclude: false, + restrict: 'C', + scope: { + 'command': '=command' + }, + controller: function($scope, $element, $sanitize) { + var registryHandlers = { + 'quay.io': function(pieces) { + var rnamespace = pieces[pieces.length - 2]; + var rname = pieces[pieces.length - 1]; + return '/repository/' + rnamespace + '/' + rname + '/'; + }, + + '': function(pieces) { + var rnamespace = pieces.length == 1 ? '_' : pieces[0]; + var rname = pieces[pieces.length - 1]; + return 'https://index.docker.io/' + rnamespace + '/' + rname + '/'; + } + }; + + var kindHandlers = { + 'FROM': function(title) { + var pieces = title.split('/'); + var registry = pieces.length < 2 ? '' : pieces[0]; + if (!registryHandlers[registry]) { + return title; + } + + return ' ' + title + ''; + } + }; + + $scope.getCommandKind = function(fullTitle) { + var colon = fullTitle.indexOf(':'); + var title = getTitleWithoutStep(fullTitle); + if (!title) { + return null; + } + + var space = title.indexOf(' '); + return title.substring(0, space); + }; + + $scope.getCommandTitleHtml = function(fullTitle) { + var title = getTitleWithoutStep(fullTitle) || fullTitle; + var space = title.indexOf(' '); + if (space <= 0) { + return $sanitize(title); + } + + var kind = $scope.getCommandKind(fullTitle); + var sanitized = $sanitize(title.substring(space + 1)); + + var handler = kindHandlers[kind || '']; + if (handler) { + return handler(sanitized); + } else { + return sanitized; + } + }; + + var getTitleWithoutStep = function(fullTitle) { + var colon = fullTitle.indexOf(':'); + if (colon <= 0) { + return null; + } + + return $.trim(fullTitle.substring(colon + 1)); + }; + } + }; + return directiveDefinitionObject; +}); + quayApp.directive('buildStatus', function () { var directiveDefinitionObject = { priority: 0, @@ -2501,17 +2614,17 @@ quayApp.directive('buildMessage', function () { transclude: false, restrict: 'C', scope: { - 'build': '=build' + 'phase': '=phase' }, controller: function($scope, $element) { - $scope.getBuildMessage = function (buildInfo) { - switch (buildInfo.phase) { + $scope.getBuildMessage = function (phase) { + switch (phase) { case 'starting': case 'initializing': return 'Starting Dockerfile build'; case 'waiting': - return 'Waiting for available build worker.'; + return 'Waiting for available build worker'; case 'building': return 'Building image from Dockerfile'; @@ -2523,7 +2636,7 @@ quayApp.directive('buildMessage', function () { return 'Dockerfile build completed and pushed'; case 'error': - return 'Dockerfile build failed.'; + return 'Dockerfile build failed'; } }; } diff --git a/static/js/controllers.js b/static/js/controllers.js index 0f8682c91..1dbade8eb 100644 --- a/static/js/controllers.js +++ b/static/js/controllers.js @@ -624,32 +624,6 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope var name = $routeParams.name; var pollTimerHandle = null; - var registryHandlers = { - 'quay.io': function(pieces) { - var rnamespace = pieces[pieces.length - 2]; - var rname = pieces[pieces.length - 1]; - return '/repository/' + rnamespace + '/' + rname + '/'; - }, - - '': function(pieces) { - var rnamespace = pieces.length == 1 ? '_' : pieces[0]; - var rname = pieces[pieces.length - 1]; - return 'https://index.docker.io/' + rnamespace + '/' + rname + '/'; - } - }; - - var kindHandlers = { - 'FROM': function(title) { - var pieces = title.split('/'); - var registry = pieces.length < 2 ? '' : pieces[0]; - if (!registryHandlers[registry]) { - return title; - } - - return ' ' + title + ''; - } - }; - $scope.$on('$destroy', function() { stopPollTimer(); }); @@ -668,43 +642,19 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope $('.build-logs').height($(window).height() - 365); }; - $scope.getCommandKind = function(fullTitle) { - var colon = fullTitle.indexOf(':'); - var title = getTitleWithoutStep(fullTitle); - if (!title) { - return null; - } - - var space = title.indexOf(' '); - return title.substring(0, space); + $scope.hasLogs = function(container) { + return ((container.logs && container.logs.length) || (container._logs && container._logs.length)); }; - $scope.getCommandTitleHtml = function(fullTitle) { - var title = getTitleWithoutStep(fullTitle) || fullTitle; - var space = title.indexOf(' '); - if (space <= 0) { - return $sanitize(title); - } - - var kind = $scope.getCommandKind(fullTitle); - var sanitized = $sanitize(title.substring(space + 1)); - - var handler = kindHandlers[kind || '']; - if (handler) { - return handler(sanitized); + $scope.toggleLogs = function(container) { + if (container._logs) { + container.logs = container._logs; + container._logs = null; } else { - return sanitized; + container._logs = container.logs; + container.logs = null; } - }; - - $scope.toggleCommand = function(command) { - command.expanded = !command.expanded; - - if (command.expanded && !command.logs) { - // Load the logs for the command. - loadCommandLogs(command); - } - }; + }; $scope.setCurrentBuild = function(buildId, opt_updateURL) { // Find the build. @@ -721,10 +671,10 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope stopPollTimer(); - $scope.commands = null; - $scope.commandMap = {}; - $scope.logs = null; + $scope.logEntries = null; $scope.logStartIndex = null; + $scope.currentParentEntry = null; + $scope.currentBuild = build; if (opt_updateURL) { @@ -748,15 +698,6 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope checkPollTimer(); }; - var getTitleWithoutStep = function(fullTitle) { - var colon = fullTitle.indexOf(':'); - if (colon <= 0) { - return null; - } - - return $.trim(fullTitle.substring(colon + 1)); - } - var checkPollTimer = function() { var build = $scope.currentBuild; if (!build) { @@ -783,65 +724,25 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope }; var processLogs = function(logs, startIndex) { - var currentCommand = $scope.commands.length > 0 ? $scope.commands[$scope.commands.length - 1] : null; + if (!$scope.logEntries) { $scope.logEntries = []; } + for (var i = 0; i < logs.length; ++i) { var entry = logs[i]; - if (entry['is_command']) { - var index = startIndex + i; - var existing = $scope.commandMap[index]; - if (existing) { - currentCommand = existing; - continue; + var type = entry['type'] || 'entry'; + if (type == 'command' || type == 'phase' || type == 'error') { + entry['_logs'] = []; + entry['index'] = startIndex + i; + + $scope.logEntries.push(entry); + $scope.currentParentEntry = entry; + } else if ($scope.currentParentEntry) { + if ($scope.currentParentEntry['logs']) { + $scope.currentParentEntry['logs'].push(entry); + } else { + $scope.currentParentEntry['_logs'].push(entry); } - - currentCommand = { - 'message': entry['message'], - 'index': index - }; - $scope.commands.push(currentCommand); - $scope.commandMap[index] = currentCommand; - continue; } - - if (!currentCommand.logs) { - currentCommand.logs = []; - } - currentCommand.logs.push(entry); } - - if (currentCommand.expanded == null) { - currentCommand.expanded = true; - } - }; - - var loadCommandLogs = function(command) { - var start = command['index'] + 1; - var end = null; - - var currentCommandIndex = jQuery.inArray(command, $scope.commands); - if (currentCommandIndex >= 0 && currentCommandIndex < $scope.commands.length - 1) { - var nextCommand = $scope.commands[currentCommandIndex + 1]; - end = nextCommand.index ? nextCommand.index - 1 : null; - } - - var params = { - 'repository': namespace + '/' + name, - 'build_uuid': $scope.currentBuild.id - }; - - var options = { - 'start': start - }; - - if (end != null) { - options['end'] = end; - } - - ApiService.getRepoBuildLogsAsResource(params, true).withOptions(options).get(function(resp) { - if (resp['logs']) { - command.logs = resp['logs']; - } - }); }; var getBuildStatusAndLogs = function() { @@ -862,20 +763,10 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope // Load the updated logs for the build. var options = { - 'commands': $scope.commands == null, 'start': $scope.logStartIndex }; - ApiService.getRepoBuildLogsAsResource(params, true).withOptions(options).get(function(resp) { - if (resp['commands']) { - $scope.commands = resp['commands']; - - // Add the commands to the map. - for (var i = 0; i < $scope.commands.length; ++i) { - var command = $scope.commands[i]; - $scope.commandMap[command['index']] = command; - } - } + ApiService.getRepoBuildLogsAsResource(params, true).withOptions(options).get(function(resp) { processLogs(resp['logs'], resp['start']); $scope.logStartIndex = resp['total']; $scope.polling = false; diff --git a/static/partials/repo-build.html b/static/partials/repo-build.html index 828ce5797..7037363e7 100644 --- a/static/partials/repo-build.html +++ b/static/partials/repo-build.html @@ -8,11 +8,11 @@
-
- There are no active builds for this repository +
+ There are no builds for this repository
-
+
- +
-
+
-
-
- - - - - - -
-
-
- - + +
+
+ +
+
-
- +
+ +
+
+ +
+
+ + +
+
+ +