Merge branch 'master' into nolurk
This commit is contained in:
commit
c0e995c1d4
43 changed files with 1091 additions and 127 deletions
|
@ -388,6 +388,29 @@ a:focus {
|
|||
width: 400px;
|
||||
}
|
||||
|
||||
.config-map-field-element table {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.config-map-field-element .form-control-container {
|
||||
border-top: 1px solid #eee;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.config-map-field-element .form-control-container select, .config-map-field-element .form-control-container input {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.config-map-field-element .empty {
|
||||
color: #ccc;
|
||||
margin-bottom: 10px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.config-map-field-element .item-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.config-contact-field {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
|
|
@ -157,6 +157,24 @@
|
|||
transition: all 0.15s ease-in-out;
|
||||
}
|
||||
|
||||
.build-logs-view .download-button i.fa {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.build-logs-view .download-button {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 124px;
|
||||
z-index: 2;
|
||||
transition: all 0.15s ease-in-out;
|
||||
}
|
||||
|
||||
.build-logs-view .download-button:not(:hover) {
|
||||
background: transparent;
|
||||
border: 1px solid transparent;
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
.build-logs-view .copy-button:not(.zeroclipboard-is-hover) {
|
||||
background: transparent;
|
||||
border: 1px solid transparent;
|
||||
|
|
|
@ -3,6 +3,12 @@
|
|||
<i class="fa fa-clipboard"></i>Copy Logs
|
||||
</button>
|
||||
|
||||
<a id="downloadButton" class="btn btn-primary download-button"
|
||||
ng-href="/buildlogs/{{ currentBuild.id }}"
|
||||
target="_blank">
|
||||
<i class="fa fa-download"></i>Download Logs
|
||||
</a>
|
||||
|
||||
<span class="cor-loader" ng-if="!logEntries"></span>
|
||||
|
||||
<span class="no-logs" ng-if="!logEntries.length && currentBuild.phase == 'waiting'">
|
||||
|
|
20
static/directives/config/config-map-field.html
Normal file
20
static/directives/config/config-map-field.html
Normal file
|
@ -0,0 +1,20 @@
|
|||
<div class="config-map-field-element">
|
||||
<table class="table" ng-show="hasValues(binding)">
|
||||
<tr class="item" ng-repeat="(key, value) in binding">
|
||||
<td class="item-title">{{ key }}</td>
|
||||
<td class="item-value">{{ value }}</td>
|
||||
<td class="item-delete">
|
||||
<a href="javascript:void(0)" ng-click="removeKey(key)">Remove</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<span class="empty" ng-if="!hasValues(binding)">No entries defined</span>
|
||||
<form class="form-control-container" ng-submit="addEntry()">
|
||||
Add Key-Value:
|
||||
<select ng-model="newKey">
|
||||
<option ng-repeat="key in keys" value="{{ key }}">{{ key }}</option>
|
||||
</select>
|
||||
<input type="text" class="form-control" placeholder="Value" ng-model="newValue">
|
||||
<button class="btn btn-default" style="display: inline-block">Add Entry</button>
|
||||
</form>
|
||||
</div>
|
|
@ -112,6 +112,11 @@
|
|||
A valid SSL certificate and private key files are required to use this option.
|
||||
</div>
|
||||
|
||||
<div class="co-alert co-alert-info" ng-if="config.PREFERRED_URL_SCHEME == 'https'">
|
||||
Enabling SSL also enables <a href="https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security">HTTP Strict Transport Security</a>.<br/>
|
||||
This prevents downgrade attacks and cookie theft, but browsers will reject all future insecure connections on this hostname.
|
||||
</div>
|
||||
|
||||
<table class="config-table" ng-if="config.PREFERRED_URL_SCHEME == 'https'">
|
||||
<tr>
|
||||
<td class="non-input">Certificate:</td>
|
||||
|
@ -198,6 +203,7 @@
|
|||
<option value="S3Storage">Amazon S3</option>
|
||||
<option value="GoogleCloudStorage">Google Cloud Storage</option>
|
||||
<option value="RadosGWStorage">Ceph Object Gateway (RADOS)</option>
|
||||
<option value="SwiftStorage">OpenStack Storage (Swift)</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -206,10 +212,15 @@
|
|||
<tr ng-repeat="field in STORAGE_CONFIG_FIELDS[config.DISTRIBUTED_STORAGE_CONFIG.local[0]]">
|
||||
<td>{{ field.title }}:</td>
|
||||
<td>
|
||||
<span class="config-map-field"
|
||||
binding="config.DISTRIBUTED_STORAGE_CONFIG.local[1][field.name]"
|
||||
ng-if="field.kind == 'map'"
|
||||
keys="field.keys"></span>
|
||||
<span class="config-string-field"
|
||||
binding="config.DISTRIBUTED_STORAGE_CONFIG.local[1][field.name]"
|
||||
placeholder="{{ field.placeholder }}"
|
||||
ng-if="field.kind == 'text'"></span>
|
||||
ng-if="field.kind == 'text'"
|
||||
is-optional="field.optional"></span>
|
||||
<div class="co-checkbox" ng-if="field.kind == 'bool'">
|
||||
<input id="dsc-{{ field.name }}" type="checkbox"
|
||||
ng-model="config.DISTRIBUTED_STORAGE_CONFIG.local[1][field.name]">
|
||||
|
@ -849,4 +860,4 @@
|
|||
</div><!-- /.modal -->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<form name="fieldform" novalidate>
|
||||
<input type="text" class="form-control" placeholder="{{ placeholder || '' }}"
|
||||
ng-model="binding" ng-trim="false" ng-minlength="1"
|
||||
ng-pattern="getRegexp(pattern)" required>
|
||||
ng-pattern="getRegexp(pattern)" ng-required="!isOptional">
|
||||
<div class="alert alert-danger" ng-show="errorMessage">
|
||||
{{ errorMessage }}
|
||||
</div>
|
||||
|
|
|
@ -63,6 +63,12 @@
|
|||
|
||||
<!-- Build Status Badge -->
|
||||
<div class="panel-body panel-section hidden-xs">
|
||||
|
||||
<!-- Token Info Banner -->
|
||||
<div class="co-alert co-alert-info" ng-if="!repository.is_public">
|
||||
Note: This badge contains a token so the badge can be seen by external users. The token does not grant any other access and is safe to share!
|
||||
</div>
|
||||
|
||||
<!-- Status Image -->
|
||||
<a ng-href="/repository/{{ repository.namespace }}/{{ repository.name }}">
|
||||
<img ng-src="/repository/{{ repository.namespace }}/{{ repository.name }}/status?token={{ repository.status_token }}"
|
||||
|
|
|
@ -15,10 +15,10 @@
|
|||
|
||||
<div class="empty" ng-if="!notifications.length">
|
||||
<div class="empty-primary-msg">No notifications have been setup for this repository.</div>
|
||||
<div class="empty-secondary-msg hidden-xs" ng-if="repository.can_write">
|
||||
<div class="empty-secondary-msg hidden-sm hidden-xs" ng-if="repository.can_write">
|
||||
Click the "Create Notification" button above to add a new notification for a repository event.
|
||||
</div>
|
||||
<div class="empty-secondary-msg visible-xs" ng-if="repository.can_write">
|
||||
<div class="empty-secondary-msg visible-sm visible-xs" ng-if="repository.can_write">
|
||||
<a href="javascript:void(0)" ng-click="askCreateNotification()">Click here</a> to add a new notification for a repository event.
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -78,6 +78,19 @@ angular.module("core-config-setup", ['angularFileUpload'])
|
|||
{'name': 'secret_key', 'title': 'Secret Key', 'placeholder': 'secretkeyhere', 'kind': 'text'},
|
||||
{'name': 'bucket_name', 'title': 'Bucket Name', 'placeholder': 'my-cool-bucket', 'kind': 'text'},
|
||||
{'name': 'storage_path', 'title': 'Storage Directory', 'placeholder': '/path/inside/bucket', 'kind': 'text'}
|
||||
],
|
||||
|
||||
'SwiftStorage': [
|
||||
{'name': 'auth_url', 'title': 'Swift Auth URL', 'placeholder': '', 'kind': 'text'},
|
||||
{'name': 'swift_container', 'title': 'Swift Container Name', 'placeholder': 'mycontainer', 'kind': 'text'},
|
||||
{'name': 'storage_path', 'title': 'Storage Path', 'placeholder': '/path/inside/container', 'kind': 'text'},
|
||||
|
||||
{'name': 'swift_user', 'title': 'Username', 'placeholder': 'accesskeyhere', 'kind': 'text'},
|
||||
{'name': 'swift_password', 'title': 'Password/Key', 'placeholder': 'secretkeyhere', 'kind': 'text'},
|
||||
|
||||
{'name': 'ca_cert_path', 'title': 'CA Cert Filename', 'placeholder': 'conf/stack/swift.cert', 'kind': 'text', 'optional': true},
|
||||
{'name': 'os_options', 'title': 'OS Options', 'kind': 'map',
|
||||
'keys': ['tenant_id', 'auth_token', 'service_type', 'endpoint_type', 'tenant_name', 'object_storage_url', 'region_name']}
|
||||
]
|
||||
};
|
||||
|
||||
|
@ -760,6 +773,42 @@ angular.module("core-config-setup", ['angularFileUpload'])
|
|||
return directiveDefinitionObject;
|
||||
})
|
||||
|
||||
.directive('configMapField', function () {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 0,
|
||||
templateUrl: '/static/directives/config/config-map-field.html',
|
||||
replace: false,
|
||||
transclude: false,
|
||||
restrict: 'C',
|
||||
scope: {
|
||||
'binding': '=binding',
|
||||
'keys': '=keys'
|
||||
},
|
||||
controller: function($scope, $element) {
|
||||
$scope.newKey = null;
|
||||
$scope.newValue = null;
|
||||
|
||||
$scope.hasValues = function(binding) {
|
||||
return binding && Object.keys(binding).length;
|
||||
};
|
||||
|
||||
$scope.removeKey = function(key) {
|
||||
delete $scope.binding[key];
|
||||
};
|
||||
|
||||
$scope.addEntry = function() {
|
||||
if (!$scope.newKey || !$scope.newValue) { return; }
|
||||
|
||||
$scope.binding = $scope.binding || {};
|
||||
$scope.binding[$scope.newKey] = $scope.newValue;
|
||||
$scope.newKey = null;
|
||||
$scope.newValue = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
})
|
||||
|
||||
.directive('configStringField', function () {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 0,
|
||||
|
@ -772,7 +821,8 @@ angular.module("core-config-setup", ['angularFileUpload'])
|
|||
'placeholder': '@placeholder',
|
||||
'pattern': '@pattern',
|
||||
'defaultValue': '@defaultValue',
|
||||
'validator': '&validator'
|
||||
'validator': '&validator',
|
||||
'isOptional': '=isOptional'
|
||||
},
|
||||
controller: function($scope, $element) {
|
||||
$scope.getRegexp = function(pattern) {
|
||||
|
|
|
@ -260,7 +260,7 @@ angular.module('quay').directive('repoPanelBuilds', function () {
|
|||
};
|
||||
|
||||
$scope.handleBuildStarted = function(build) {
|
||||
if (!$scope.allBuilds) {
|
||||
if ($scope.allBuilds) {
|
||||
$scope.allBuilds.push(build);
|
||||
}
|
||||
updateBuilds();
|
||||
|
|
|
@ -123,6 +123,7 @@ angular.module('quay').directive('triggerSetupGithost', function () {
|
|||
|
||||
ApiService.listBuildTriggerSubdirs($scope.trigger['config'], params).then(function(resp) {
|
||||
if (resp['status'] == 'error') {
|
||||
$scope.locations = [];
|
||||
callback(resp['message'] || 'Could not load Dockerfile locations');
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
$scope.signinStarted = function() {
|
||||
if (Features.BILLING) {
|
||||
PlanService.getMinimumPlan(1, true, function(plan) {
|
||||
if (!plan) { return; }
|
||||
PlanService.notePlan(plan.stripeId);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@
|
|||
}, ApiService.errorDisplay('Could not generate token'));
|
||||
};
|
||||
|
||||
UIService.showPasswordDialog('Enter your password to generated an encrypted version:', generateToken);
|
||||
UIService.showPasswordDialog('Enter your password to generate an encrypted version:', generateToken);
|
||||
};
|
||||
|
||||
$scope.changeEmail = function() {
|
||||
|
|
9
static/js/services/angular-poll-channel.js
vendored
9
static/js/services/angular-poll-channel.js
vendored
|
@ -1,7 +1,8 @@
|
|||
/**
|
||||
* Specialized class for conducting an HTTP poll, while properly preventing multiple calls.
|
||||
*/
|
||||
angular.module('quay').factory('AngularPollChannel', ['ApiService', '$timeout', function(ApiService, $timeout) {
|
||||
angular.module('quay').factory('AngularPollChannel', ['ApiService', '$timeout', 'DocumentVisibilityService',
|
||||
function(ApiService, $timeout, DocumentVisibilityService) {
|
||||
var _PollChannel = function(scope, requester, opt_sleeptime) {
|
||||
this.scope_ = scope;
|
||||
this.requester_ = requester;
|
||||
|
@ -50,6 +51,12 @@ angular.module('quay').factory('AngularPollChannel', ['ApiService', '$timeout',
|
|||
_PollChannel.prototype.call_ = function() {
|
||||
if (this.working) { return; }
|
||||
|
||||
// If the document is currently hidden, skip the call.
|
||||
if (DocumentVisibilityService.isHidden()) {
|
||||
this.setupTimer_();
|
||||
return;
|
||||
}
|
||||
|
||||
var that = this;
|
||||
this.working = true;
|
||||
this.scope_.$apply(function() {
|
||||
|
|
60
static/js/services/document-visibility-service.js
Normal file
60
static/js/services/document-visibility-service.js
Normal file
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
* Helper service which fires off events when the document's visibility changes, as well as allowing
|
||||
* other Angular code to query the state of the document's visibility directly.
|
||||
*/
|
||||
angular.module('quay').constant('CORE_EVENT', {
|
||||
DOC_VISIBILITY_CHANGE: 'core.event.doc_visibility_change'
|
||||
});
|
||||
|
||||
angular.module('quay').factory('DocumentVisibilityService', ['$rootScope', '$document', 'CORE_EVENT',
|
||||
function($rootScope, $document, CORE_EVENT) {
|
||||
var document = $document[0],
|
||||
features,
|
||||
detectedFeature;
|
||||
|
||||
function broadcastChangeEvent() {
|
||||
$rootScope.$broadcast(CORE_EVENT.DOC_VISIBILITY_CHANGE,
|
||||
document[detectedFeature.propertyName]);
|
||||
}
|
||||
|
||||
features = {
|
||||
standard: {
|
||||
eventName: 'visibilitychange',
|
||||
propertyName: 'hidden'
|
||||
},
|
||||
moz: {
|
||||
eventName: 'mozvisibilitychange',
|
||||
propertyName: 'mozHidden'
|
||||
},
|
||||
ms: {
|
||||
eventName: 'msvisibilitychange',
|
||||
propertyName: 'msHidden'
|
||||
},
|
||||
webkit: {
|
||||
eventName: 'webkitvisibilitychange',
|
||||
propertyName: 'webkitHidden'
|
||||
}
|
||||
};
|
||||
|
||||
Object.keys(features).some(function(feature) {
|
||||
if (document[features[feature].propertyName] !== undefined) {
|
||||
detectedFeature = features[feature];
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
if (detectedFeature) {
|
||||
$document.on(detectedFeature.eventName, broadcastChangeEvent);
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Is the window currently hidden or not.
|
||||
*/
|
||||
isHidden: function() {
|
||||
if (detectedFeature) {
|
||||
return document[detectedFeature.propertyName];
|
||||
}
|
||||
}
|
||||
};
|
||||
}]);
|
|
@ -196,6 +196,10 @@ function($rootScope, $interval, UserService, ApiService, StringBuilderService, P
|
|||
};
|
||||
|
||||
notificationService.getClasses = function(notifications) {
|
||||
if (!notifications.length) {
|
||||
return '';
|
||||
}
|
||||
|
||||
var classes = [];
|
||||
for (var i = 0; i < notifications.length; ++i) {
|
||||
var notification = notifications[i];
|
||||
|
|
|
@ -122,7 +122,7 @@ angular.module('quay').factory('TriggerService', ['UtilService', '$sanitize', 'K
|
|||
'title': 'Commit',
|
||||
'type': 'regex',
|
||||
'name': 'commit_sha',
|
||||
'regex': '^([A-Fa-f0-9]{7})$',
|
||||
'regex': '^([A-Fa-f0-9]{7,})$',
|
||||
'placeholder': '1c002dd'
|
||||
}
|
||||
],
|
||||
|
|
Reference in a new issue