- Switch to new typeahead (based on our own branch of it until such time as it gets pulled into the mainline) and add an informative empty message on entity search
- Add better messaging around pushing to empty repos
This commit is contained in:
parent
536a91cbb8
commit
2a8669b2f4
8 changed files with 153 additions and 56 deletions
|
@ -1538,10 +1538,17 @@ p.editable:hover i {
|
||||||
}
|
}
|
||||||
|
|
||||||
.repo .empty-description {
|
.repo .empty-description {
|
||||||
max-width: 600px;
|
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.repo .empty-description pre:last-child {
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.repo .empty-description .panel-default {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
.repo dl.dl-horizontal dt {
|
.repo dl.dl-horizontal dt {
|
||||||
width: 80px;
|
width: 80px;
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
|
@ -2834,9 +2841,10 @@ p.editable:hover i {
|
||||||
.tt-suggestion {
|
.tt-suggestion {
|
||||||
display: block;
|
display: block;
|
||||||
padding: 3px 20px;
|
padding: 3px 20px;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tt-suggestion.tt-is-under-cursor {
|
.tt-suggestion.tt-cursor {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background-color: #0081c2;
|
background-color: #0081c2;
|
||||||
background-image: -moz-linear-gradient(top, #0088cc, #0077b3);
|
background-image: -moz-linear-gradient(top, #0088cc, #0077b3);
|
||||||
|
@ -2848,10 +2856,17 @@ p.editable:hover i {
|
||||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0)
|
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0)
|
||||||
}
|
}
|
||||||
|
|
||||||
.tt-suggestion.tt-is-under-cursor a {
|
.tt-suggestion.tt-cursor a {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tt-empty {
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #aaa;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
.tt-suggestion p {
|
.tt-suggestion p {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
<div class="slideinout" ng-show="currentRepo">
|
<div class="slideinout" ng-show="currentRepo">
|
||||||
<div style="margin-top: 10px">Dockerfile Location:</div>
|
<div style="margin-top: 10px">Dockerfile Location:</div>
|
||||||
<div class="dropdown-select" placeholder="'(Repository Root)'" selected-item="currentLocation"
|
<div class="dropdown-select" placeholder="'(Repository Root)'" selected-item="currentLocation"
|
||||||
lookahead-items="locations" handle-input="handleLocationInput(input)">
|
lookahead-items="locations" handle-input="handleLocationInput(input)" handle-item-selected="handleLocationSelected(datum)">
|
||||||
<!-- Icons -->
|
<!-- Icons -->
|
||||||
<i class="dropdown-select-icon none-icon fa fa-folder-o fa-lg" ng-show="isInvalidLocation"></i>
|
<i class="dropdown-select-icon none-icon fa fa-folder-o fa-lg" ng-show="isInvalidLocation"></i>
|
||||||
<i class="dropdown-select-icon none-icon fa fa-folder fa-lg" style="color: black;" ng-show="!isInvalidLocation"></i>
|
<i class="dropdown-select-icon none-icon fa fa-folder fa-lg" style="color: black;" ng-show="!isInvalidLocation"></i>
|
||||||
|
|
|
@ -2008,8 +2008,7 @@ quayApp.directive('repoSearch', function () {
|
||||||
++searchToken;
|
++searchToken;
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
var element = $($element[0].childNodes[0]);
|
var repoHound = new Bloodhound({
|
||||||
element.typeahead({
|
|
||||||
name: 'repositories',
|
name: 'repositories',
|
||||||
remote: {
|
remote: {
|
||||||
url: '/api/find/repository?query=%QUERY',
|
url: '/api/find/repository?query=%QUERY',
|
||||||
|
@ -2031,7 +2030,18 @@ quayApp.directive('repoSearch', function () {
|
||||||
return datums;
|
return datums;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: function (datum) {
|
datumTokenizer: function(d) {
|
||||||
|
return Bloodhound.tokenizers.whitespace(d.val);
|
||||||
|
},
|
||||||
|
queryTokenizer: Bloodhound.tokenizers.whitespace
|
||||||
|
});
|
||||||
|
repoHound.initialize();
|
||||||
|
|
||||||
|
var element = $($element[0].childNodes[0]);
|
||||||
|
element.typeahead({ 'highlight': true }, {
|
||||||
|
source: repoHound.ttAdapter(),
|
||||||
|
templates: {
|
||||||
|
'suggestion': function (datum) {
|
||||||
template = '<div class="repo-mini-listing">';
|
template = '<div class="repo-mini-listing">';
|
||||||
template += '<i class="fa fa-hdd-o fa-lg"></i>'
|
template += '<i class="fa fa-hdd-o fa-lg"></i>'
|
||||||
template += '<span class="name">' + datum.repo.namespace +'/' + datum.repo.name + '</span>'
|
template += '<span class="name">' + datum.repo.namespace +'/' + datum.repo.name + '</span>'
|
||||||
|
@ -2042,11 +2052,14 @@ quayApp.directive('repoSearch', function () {
|
||||||
template += '</div>'
|
template += '</div>'
|
||||||
return template;
|
return template;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
element.on('typeahead:selected', function (e, datum) {
|
element.on('typeahead:selected', function (e, datum) {
|
||||||
element.typeahead('setQuery', '');
|
element.typeahead('val', '');
|
||||||
document.location = '/repository/' + datum.repo.namespace + '/' + datum.repo.name;
|
$scope.$apply(function() {
|
||||||
|
$location.path('/repository/' + datum.repo.namespace + '/' + datum.repo.name);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -2213,7 +2226,7 @@ quayApp.directive('entitySearch', function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.setEntityInternal = function(entity) {
|
$scope.setEntityInternal = function(entity) {
|
||||||
$(input).typeahead('setQuery', $scope.isPersistent ? entity.name : '');
|
$(input).typeahead('val', $scope.isPersistent ? entity.name : '');
|
||||||
|
|
||||||
if ($scope.isPersistent) {
|
if ($scope.isPersistent) {
|
||||||
$scope.currentEntity = entity;
|
$scope.currentEntity = entity;
|
||||||
|
@ -2226,8 +2239,7 @@ quayApp.directive('entitySearch', function () {
|
||||||
|
|
||||||
number++;
|
number++;
|
||||||
|
|
||||||
var input = $element[0].firstChild.firstChild;
|
var entitySearchB = new Bloodhound({
|
||||||
$(input).typeahead({
|
|
||||||
name: 'entities' + number,
|
name: 'entities' + number,
|
||||||
remote: {
|
remote: {
|
||||||
url: '/api/entities/%QUERY',
|
url: '/api/entities/%QUERY',
|
||||||
|
@ -2253,7 +2265,40 @@ quayApp.directive('entitySearch', function () {
|
||||||
return datums;
|
return datums;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: function (datum) {
|
datumTokenizer: function(d) {
|
||||||
|
return Bloodhound.tokenizers.whitespace(d.val);
|
||||||
|
},
|
||||||
|
queryTokenizer: Bloodhound.tokenizers.whitespace
|
||||||
|
});
|
||||||
|
entitySearchB.initialize();
|
||||||
|
|
||||||
|
var counter = 0;
|
||||||
|
var input = $element[0].firstChild.firstChild;
|
||||||
|
$(input).typeahead({
|
||||||
|
'highlight': true
|
||||||
|
}, {
|
||||||
|
source: entitySearchB.ttAdapter(),
|
||||||
|
templates: {
|
||||||
|
'empty': function(info) {
|
||||||
|
// Only display the empty dialog if the server load has finished.
|
||||||
|
if (info.resultKind == 'remote') {
|
||||||
|
var val = $(input).val();
|
||||||
|
if (!val) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val.indexOf('@') > 0) {
|
||||||
|
return '<div class="tt-empty">A Quay.io username (not an e-mail address) must be specified</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
var robots = $scope.isOrganization ? ', robot accounts' : '';
|
||||||
|
var teams = ($scope.includeTeams && $scope.isOrganization) ? ' or teams' : '';
|
||||||
|
return '<div class="tt-empty">No matching Quay.io users' + robots + teams + ' found</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
'suggestion': function (datum) {
|
||||||
template = '<div class="entity-mini-listing">';
|
template = '<div class="entity-mini-listing">';
|
||||||
if (datum.entity.kind == 'user' && !datum.entity.is_robot) {
|
if (datum.entity.kind == 'user' && !datum.entity.is_robot) {
|
||||||
template += '<i class="fa fa-user fa-lg"></i>';
|
template += '<i class="fa fa-user fa-lg"></i>';
|
||||||
|
@ -2270,7 +2315,7 @@ quayApp.directive('entitySearch', function () {
|
||||||
|
|
||||||
template += '</div>';
|
template += '</div>';
|
||||||
return template;
|
return template;
|
||||||
},
|
}}
|
||||||
});
|
});
|
||||||
|
|
||||||
$(input).on('input', function(e) {
|
$(input).on('input', function(e) {
|
||||||
|
@ -2288,7 +2333,7 @@ quayApp.directive('entitySearch', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
$scope.$watch('clearNow', function() {
|
$scope.$watch('clearNow', function() {
|
||||||
$(input).typeahead('setQuery', '');
|
$(input).typeahead('val', '');
|
||||||
$scope.clearEntityInternal();
|
$scope.clearEntityInternal();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2722,13 +2767,35 @@ quayApp.directive('dropdownSelect', function ($compile) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$(input).typeahead({
|
var formattedItems = [];
|
||||||
|
for (var i = 0; i < items.length; ++i) {
|
||||||
|
var formattedItem = items[i];
|
||||||
|
if (typeof formattedItem == 'string') {
|
||||||
|
formattedItem = {
|
||||||
|
'value': formattedItem
|
||||||
|
};
|
||||||
|
}
|
||||||
|
formattedItems.push(formattedItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
var dropdownHound = new Bloodhound({
|
||||||
name: 'dropdown-items-' + $rootScope.__dropdownSelectCounter,
|
name: 'dropdown-items-' + $rootScope.__dropdownSelectCounter,
|
||||||
local: items,
|
local: formattedItems,
|
||||||
template: function (datum) {
|
datumTokenizer: function(d) {
|
||||||
|
return Bloodhound.tokenizers.whitespace(d.val || d.value || '');
|
||||||
|
},
|
||||||
|
queryTokenizer: Bloodhound.tokenizers.whitespace
|
||||||
|
});
|
||||||
|
dropdownHound.initialize();
|
||||||
|
|
||||||
|
$(input).typeahead({}, {
|
||||||
|
source: dropdownHound.ttAdapter(),
|
||||||
|
templates: {
|
||||||
|
'suggestion': function (datum) {
|
||||||
template = datum['template'] ? datum['template'](datum) : datum['value'];
|
template = datum['template'] ? datum['template'](datum) : datum['value'];
|
||||||
return template;
|
return template;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$(input).on('input', function(e) {
|
$(input).on('input', function(e) {
|
||||||
|
@ -2830,6 +2897,10 @@ quayApp.directive('triggerSetupGithub', function () {
|
||||||
$scope.isInvalidLocation = $scope.locations.indexOf(location) < 0;
|
$scope.isInvalidLocation = $scope.locations.indexOf(location) < 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.handleLocationSelected = function(datum) {
|
||||||
|
$scope.setLocation(datum['value']);
|
||||||
|
};
|
||||||
|
|
||||||
$scope.setLocation = function(location) {
|
$scope.setLocation = function(location) {
|
||||||
$scope.currentLocation = location;
|
$scope.currentLocation = location;
|
||||||
$scope.trigger['config']['subdir'] = location || '';
|
$scope.trigger['config']['subdir'] = location || '';
|
||||||
|
|
7
static/lib/typeahead.bundle.min.js
vendored
Normal file
7
static/lib/typeahead.bundle.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7
static/lib/typeahead.min.js
vendored
7
static/lib/typeahead.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
<tr ng-show="canEditMembers">
|
<tr ng-show="canEditMembers">
|
||||||
<td colspan="2">
|
<td colspan="2">
|
||||||
<span class="entity-search" namespace="orgname" include-teams="false" input-title="'Add a user...'"
|
<span class="entity-search" namespace="orgname" include-teams="false" input-title="'Add a Quay.io user...'"
|
||||||
entity-selected="addNewMember" is-organization="true"
|
entity-selected="addNewMember" is-organization="true"
|
||||||
current-entity="selectedMember"></span>
|
current-entity="selectedMember"></span>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -82,11 +82,22 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="empty-description" ng-show="repo.can_write">
|
<div class="empty-description" ng-show="repo.can_write">
|
||||||
To push images to this repository:<br><br>
|
<div class="panel-default">
|
||||||
<pre>sudo docker tag <i>0u123imageidgoeshere</i> quay.io/{{repo.namespace}}/{{repo.name}}
|
<div class="panel-heading">How to push a new image to this repository:</div>
|
||||||
sudo docker push quay.io/{{repo.namespace}}/{{repo.name}}</pre>
|
<div class="panel-body">
|
||||||
|
First login to Quay.io (if you have not done so already):
|
||||||
|
<pre class="command">sudo docker login quay.io</pre>
|
||||||
|
|
||||||
|
Tag an image to this repository:
|
||||||
|
<pre class="command">sudo docker tag <i>0u123imageidgoeshere</i> quay.io/{{repo.namespace}}/{{repo.name}}</pre>
|
||||||
|
|
||||||
|
Push the image to this repository:
|
||||||
|
<pre class="command">sudo docker push quay.io/{{repo.namespace}}/{{repo.name}}</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="repo-content" ng-show="!currentTag.image && repo.is_building">
|
<div class="repo-content" ng-show="!currentTag.image && repo.is_building">
|
||||||
<div class="empty-message">
|
<div class="empty-message">
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.1/angular-animate.min.js"></script>
|
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.1/angular-animate.min.js"></script>
|
||||||
|
|
||||||
<script src="//cdn.jsdelivr.net/g/bootbox@4.1.0,underscorejs@1.5.2,restangular@1.2.0"></script>
|
<script src="//cdn.jsdelivr.net/g/bootbox@4.1.0,underscorejs@1.5.2,restangular@1.2.0"></script>
|
||||||
|
<!-- ,typeahead.js@0.10.1 -->
|
||||||
|
|
||||||
<script src="static/lib/loading-bar.js"></script>
|
<script src="static/lib/loading-bar.js"></script>
|
||||||
<script src="static/lib/angular-strap.min.js"></script>
|
<script src="static/lib/angular-strap.min.js"></script>
|
||||||
|
@ -54,12 +55,11 @@
|
||||||
<script src="static/lib/angular-md5.js"></script>
|
<script src="static/lib/angular-md5.js"></script>
|
||||||
<script src="static/lib/bindonce.min.js"></script>
|
<script src="static/lib/bindonce.min.js"></script>
|
||||||
<script src="static/lib/ansi2html.js"></script>
|
<script src="static/lib/ansi2html.js"></script>
|
||||||
|
<script src="static/lib/typeahead.bundle.min.js"></script>
|
||||||
|
|
||||||
<script src="static/lib/angular-moment.min.js"></script>
|
<script src="static/lib/angular-moment.min.js"></script>
|
||||||
<script src="static/lib/angular-cookies.min.js"></script>
|
<script src="static/lib/angular-cookies.min.js"></script>
|
||||||
|
|
||||||
<script src="static/lib/typeahead.min.js"></script>
|
|
||||||
|
|
||||||
<script src="static/lib/pagedown/Markdown.Converter.js"></script>
|
<script src="static/lib/pagedown/Markdown.Converter.js"></script>
|
||||||
<script src="static/lib/pagedown/Markdown.Editor.js"></script>
|
<script src="static/lib/pagedown/Markdown.Editor.js"></script>
|
||||||
<script src="static/lib/pagedown/Markdown.Sanitizer.js"></script>
|
<script src="static/lib/pagedown/Markdown.Sanitizer.js"></script>
|
||||||
|
|
Reference in a new issue