Merge remote-tracking branch 'origin/spartan'

Conflicts:
	test/data/test.db
This commit is contained in:
yackob03 2014-01-08 17:04:40 -05:00
commit 4234ceabe6
10 changed files with 246 additions and 10 deletions

View file

@ -1156,6 +1156,34 @@ p.editable:hover i {
font-size: 1.15em;
}
#tagContextMenu {
display: none;
position: absolute;
z-index: 100000;
outline: none;
}
#tagContextMenu ul {
display: block;
position: static;
margin-bottom: 5px;
}
.tag-controls {
display: inline-block;
margin-right: 20px;
margin-top: 2px;
opacity: 0;
float: right;
-webkit-transition: opacity 200ms ease-in-out;
-moz-transition: opacity 200ms ease-in-out;
transition: opacity 200ms ease-in-out;
}
.tag-heading:hover .tag-controls {
opacity: 1;
}
.right-title {
display: inline-block;
float: right;

View file

@ -194,6 +194,38 @@ function RepoCtrl($scope, Restangular, ApiService, $routeParams, $rootScope, $lo
}
};
$scope.askDeleteTag = function(tagName) {
if (!$scope.repo.can_admin) { return; }
$scope.tagToDelete = tagName;
$('#confirmdeleteTagModal').modal('show');
};
$scope.deleteTag = function(tagName) {
if (!$scope.repo.can_admin) { return; }
$('#confirmdeleteTagModal').modal('hide');
var params = {
'repository': namespace + '/' + name,
'tag': tagName
};
ApiService.deleteFullTag(null, params).then(function() {
loadViewInfo();
}, function(resp) {
bootbox.dialog({
"message": resp.data ? resp.data : 'Could not delete tag',
"title": "Cannot delete tag",
"buttons": {
"close": {
"label": "Close",
"className": "btn-primary"
}
}
});
});
};
$scope.setTag = function(tagName, opt_updateURL) {
var repo = $scope.repo;
var proposedTag = repo.tags[tagName];
@ -218,6 +250,11 @@ function RepoCtrl($scope, Restangular, ApiService, $routeParams, $rootScope, $lo
$location.search('tag', $scope.currentTag.name);
}
}
if ($scope.currentTag && !repo.tags[$scope.currentTag.name]) {
$scope.currentTag = null;
$scope.currentImage = null;
}
};
$scope.getTagCount = function(repo) {
@ -229,6 +266,40 @@ function RepoCtrl($scope, Restangular, ApiService, $routeParams, $rootScope, $lo
return count;
};
$scope.hideTagMenu = function(tagName, clientX, clientY) {
$scope.currentMenuTag = null;
var tagMenu = $("#tagContextMenu");
tagMenu.hide();
};
$scope.showTagMenu = function(tagName, clientX, clientY) {
if (!$scope.repo.can_admin) { return; }
$scope.currentMenuTag = tagName;
var tagMenu = $("#tagContextMenu");
tagMenu.css({
display: "block",
left: clientX,
top: clientY
});
tagMenu.on("blur", function() {
setTimeout(function() {
tagMenu.hide();
}, 100); // Needed to allow clicking on menu items.
});
tagMenu.on("click", "a", function() {
setTimeout(function() {
tagMenu.hide();
}, 100); // Needed to allow clicking on menu items.
});
tagMenu[0].focus();
};
var getDefaultTag = function() {
if ($scope.repo === undefined) {
return undefined;
@ -343,6 +414,14 @@ function RepoCtrl($scope, Restangular, ApiService, $routeParams, $rootScope, $lo
$scope.$apply(function() { $scope.setImage(e.image); });
});
$($scope.tree).bind('showTagMenu', function(e) {
$scope.$apply(function() { $scope.showTagMenu(e.tag, e.clientX, e.clientY); });
});
$($scope.tree).bind('hideTagMenu', function(e) {
$scope.$apply(function() { $scope.hideTagMenu(); });
});
return resp.images;
});
};

View file

@ -69,6 +69,25 @@ ImageHistoryTree.prototype.calculateDimensions_ = function(container) {
};
ImageHistoryTree.prototype.setupOverscroll_ = function() {
var container = this.container_;
var that = this;
var overscroll = $('#' + container).overscroll();
overscroll.on('overscroll:dragstart', function() {
$(that).trigger({
'type': 'hideTagMenu'
});
});
overscroll.on('scroll', function() {
$(that).trigger({
'type': 'hideTagMenu'
});
});
};
/**
* Updates the dimensions of the tree.
*/
@ -88,8 +107,8 @@ ImageHistoryTree.prototype.updateDimensions_ = function() {
var boundingBox = document.getElementById(container).getBoundingClientRect();
document.getElementById(container).style.maxHeight = (viewportHeight - boundingBox.top - 150) + 'px';
$('#' + container).overscroll();
this.setupOverscroll_();
// Update the tree.
var rootSvg = this.rootSvg_;
var tree = this.tree_;
@ -183,8 +202,7 @@ ImageHistoryTree.prototype.draw = function(container) {
this.root_.y0 = 0;
this.setTag_(this.currentTag_);
$('#' + container).overscroll();
this.setupOverscroll_();
};
@ -642,7 +660,7 @@ ImageHistoryTree.prototype.update_ = function(source) {
if (tag == currentTag) {
kind = 'success';
}
html += '<span class="label label-' + kind + ' tag" data-tag="' + tag + '">' + tag + '</span>';
html += '<span class="label label-' + kind + ' tag" data-tag="' + tag + '"">' + tag + '</span>';
}
return html;
});
@ -654,6 +672,19 @@ ImageHistoryTree.prototype.update_ = function(source) {
if (tag) {
that.changeTag_(tag);
}
})
.on("contextmenu", function(d, e) {
d3.event.preventDefault();
var tag = this.getAttribute('data-tag');
if (tag) {
$(that).trigger({
'type': 'showTagMenu',
'tag': tag,
'clientX': d3.event.clientX,
'clientY': d3.event.clientY
});
}
});
// Ensure the tags are visible.

View file

@ -93,6 +93,15 @@ Email: my@email.com</pre>
</ul>
</div>
<h3>Deleting a tag <span class="label label-info">Requires Admin Access</span></h3>
<div class="container">
<div class="description-overview">
A specific tag and all its images can be deleted by right clicking on the tag in the repository history tree and choosing "Delete Tag". This will delete the tag and any images <b>unique to it</b>. Images will not be deleted until all tags sharing them are deleted.
</div>
</div>
<a name="#post-hook"></a>
<h3>Using push webhooks <span class="label label-info">Requires Admin Access</span></h3>
<div class="container">

View file

@ -1,3 +1,9 @@
<div id="tagContextMenu" class="dropdown clearfix" tabindex="-1">
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu">
<li><a tabindex="-1" href="javascript:void(0)" ng-click="askDeleteTag(currentMenuTag)">Delete Tag</a></li>
</ul>
</div>
<div class="resource-view" resource="repository" error-message="'No Repository Found'">
<div class="container repo">
<!-- Repo Header -->
@ -73,7 +79,7 @@ sudo docker push quay.io/{{repo.namespace}}/{{repo.name}}</pre>
<!-- Tree View container -->
<div class="col-md-8">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-heading tag-heading">
<!-- Tag dropdown -->
<div class="tag-dropdown dropdown" title="Tags" bs-tooltip="tooltip.title" data-placement="top">
<i class="fa fa-tag"><span class="tag-count">{{getTagCount(repo)}}</span></i>
@ -85,6 +91,9 @@ sudo docker push quay.io/{{repo.namespace}}/{{repo.name}}</pre>
</ul>
</div>
<span class="right-title">Tags</span>
<span class="tag-controls" ng-show="repo.can_admin">
<a href="javascript:void(0)" ng-click="askDeleteTag(currentTag.name)">Delete Tag</a>
</span>
</div>
<!-- Image history tree -->
@ -185,3 +194,25 @@ sudo docker push quay.io/{{repo.namespace}}/{{repo.name}}</pre>
</div>
</div>
</div>
<!-- Modal message dialog -->
<div class="modal fade" id="confirmdeleteTagModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">Delete tag <span class="label label-default tag">{{ tagToDelete }}</span>?</h4>
</div>
<div class="modal-body">
Are you sure you want to delete tag <span class="label label-default tag">{{ tagToDelete }}</span>?
<br><br>
Doing so will delete any images no attached to another tag.
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" ng-click="deleteTag(tagToDelete)">Delete Tag</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->