Update for batch deletion of repos. (#1335)

NMT
This commit is contained in:
kun wang 2017-02-08 04:15:07 -06:00 committed by yhua123
parent 27802f7620
commit 13eaedb84f
7 changed files with 167 additions and 24 deletions

View File

@ -17,13 +17,21 @@
<div class="panel panel-default" ng-repeat="repo in vm.repositories"> <div class="panel panel-default" ng-repeat="repo in vm.repositories">
<div class="panel-heading" role="tab" id="heading//$index + 1//"> <div class="panel-heading" role="tab" id="heading//$index + 1//">
<h4 class="panel-title"> <h4 class="panel-title">
<a ng-show="vm.tagCount[repo] > 0" role="button" data-toggle="collapse" data-parent="" href="?project_id=//vm.projectId//#collapse//$index + 1//" aria-expanded="true" aria-controls="collapse//$index+1//"> <div class="row">
<span class="glyphicon glyphicon-book"></span> &nbsp;//repo// &nbsp;&nbsp;<span class="badge">//vm.tagCount[repo]//</span> <div class="col-md-10" style="padding: 2px">
</a> <a ng-show="vm.tagCount[repo] > 0" role="button" data-toggle="collapse" data-parent="" href="?project_id=//vm.projectId//#collapse//$index + 1//" aria-expanded="true" aria-controls="collapse//$index+1//">
<a ng-if="vm.tagCount[repo] === 0" role="button" style="text-decoration: none;" data-toggle="collapse" data-parent="" aria-expanded="true" aria-controls="collapse//$index+1//"> <span class="glyphicon glyphicon-book"></span> &nbsp;//repo// &nbsp;&nbsp;<span class="badge">//vm.tagCount[repo]//</span>
<span class="glyphicon glyphicon-book"></span> &nbsp;//repo// &nbsp;&nbsp;<span class="badge">//vm.tagCount[repo]//</span> </a>
</a> <a ng-if="vm.tagCount[repo] === 0" role="button" style="text-decoration: none;" data-toggle="collapse" data-parent="" aria-expanded="true" aria-controls="collapse//$index+1//">
<a ng-show="vm.tagCount[repo] > 0 && vm.roleId == 1" class="pull-right" style="margin-right: 75px;" href="javascript:void(0)" ng-click="vm.deleteByRepo(repo)" title="// 'delete_repo' | tr //" loading-progress hide-target="true" toggle-in-progress="vm.toggleInProgress[repo + '|']"><span class="glyphicon glyphicon-trash"></span></a> <span class="glyphicon glyphicon-book"></span> &nbsp;//repo// &nbsp;&nbsp;<span class="badge">//vm.tagCount[repo]//</span>
</a>
</div>
<div class="col-md-2" style="padding: 2px; padding-left: 6%;">
&nbsp;&nbsp;
<input ng-if="vm.tagCount[repo] > 0 && vm.roleId == 1" type="checkbox" ng-checked="vm.selectAll[repo]" ng-click="vm.selectAllTags(repo)">
<a ng-if="vm.tagCount[repo] > 0 && vm.roleId == 1 && vm.selectedTags[repo].length > 0" href="javascript:void(0)" ng-click="vm.deleteSelectedTagsByRepo(repo)" title="// 'delete_selected_tag' | tr //" loading-progress hide-target="true" toggle-in-progress="vm.toggleInProgress[repo + '|']"><span class="glyphicon glyphicon-trash"></span></a>
</div>
</div>
</h4> </h4>
</div> </div>
<list-tag ng-show="vm.tagCount[repo] > 0" associate-id="$index + 1" repo-name="repo" tag-count="vm.tagCount" toggle-in-progress="vm.toggleInProgress" delete-by-tag="vm.deleteByTag()" role-id="//vm.roleId//"></list-tag> <list-tag ng-show="vm.tagCount[repo] > 0" associate-id="$index + 1" repo-name="repo" tag-count="vm.tagCount" toggle-in-progress="vm.toggleInProgress" delete-by-tag="vm.deleteByTag()" role-id="//vm.roleId//"></list-tag>

View File

@ -72,6 +72,12 @@
} }
}); });
$scope.$watch('vm.tagName', function(current) {
if(current) {
vm.selectedTags = [];
}
});
$scope.$on('repoName', function(e, val) { $scope.$on('repoName', function(e, val) {
vm.repoName = val; vm.repoName = val;
}); });
@ -90,7 +96,16 @@
vm.deleteByRepo = deleteByRepo; vm.deleteByRepo = deleteByRepo;
vm.deleteByTag = deleteByTag; vm.deleteByTag = deleteByTag;
vm.deleteSelectedTagsByRepo = deleteSelectedTagsByRepo;
vm.deleteImage = deleteImage; vm.deleteImage = deleteImage;
vm.deleteSelectedTags = deleteSelectedTags;
vm.selectAll = [];
vm.selectAllTags = selectAllTags;
vm.selectedTags = [];
function retrieve(){ function retrieve(){
console.log('retrieve repositories, project_id:' + vm.projectId); console.log('retrieve repositories, project_id:' + vm.projectId);
@ -101,6 +116,8 @@
function getRepositoryComplete(response) { function getRepositoryComplete(response) {
vm.repositories = response.data || []; vm.repositories = response.data || [];
vm.totalCount = response.headers('X-Total-Count'); vm.totalCount = response.headers('X-Total-Count');
vm.selectAll[vm.repoName] = false;
vm.selectedTags = [];
} }
function getRepositoryFailed(response) { function getRepositoryFailed(response) {
@ -144,6 +161,30 @@
$scope.$emit('raiseInfo', emitInfo); $scope.$emit('raiseInfo', emitInfo);
} }
function deleteSelectedTagsByRepo(repo) {
vm.repoName = repo;
$scope.$broadcast('gatherSelectedTags' + vm.repoName, true);
var emitInfo = {
'confirmOnly': false,
'contentType': 'text/html',
'action' : vm.deleteSelectedTags
};
$scope.$emit('modalTitle', $filter('tr')('alert_delete_tag_title'));
$scope.$emit('modalMessage', $filter('tr')('alert_delete_selected_tag'));
$scope.$emit('raiseInfo', emitInfo);
}
function selectAllTags(repo) {
vm.selectAll[repo] = !vm.selectAll[repo];
console.log('send to tags selectAll:' + vm.selectAll[repo]);
$scope.$broadcast('selectAll' + repo, {'status': vm.selectAll[repo], 'repoName': repo});
}
$scope.$on('selectedAll', function(e, val) {
console.log('received from tags selectedAll:' + angular.toJson(val));
vm.selectAll[val.repoName] = val.status;
});
function deleteByTag() { function deleteByTag() {
$scope.$emit('modalTitle', $filter('tr')('alert_delete_tag_title', [vm.tag])); $scope.$emit('modalTitle', $filter('tr')('alert_delete_tag_title', [vm.tag]));
var message; var message;
@ -155,12 +196,10 @@
'contentType': 'text/html', 'contentType': 'text/html',
'action' : vm.deleteImage 'action' : vm.deleteImage
}; };
$scope.$emit('raiseInfo', emitInfo); $scope.$emit('raiseInfo', emitInfo);
} }
function deleteImage() { function deleteImage() {
console.log('Delete image, repoName:' + vm.repoName + ', tag:' + vm.tag); console.log('Delete image, repoName:' + vm.repoName + ', tag:' + vm.tag);
vm.toggleInProgress[vm.repoName + '|' + vm.tag] = true; vm.toggleInProgress[vm.repoName + '|' + vm.tag] = true;
DeleteRepositoryService(vm.repoName, vm.tag) DeleteRepositoryService(vm.repoName, vm.tag)
@ -168,13 +207,35 @@
.error(deleteRepositoryFailed); .error(deleteRepositoryFailed);
} }
$scope.$on('selectedTags', function(e, val) {
if(val) {
vm.selectedTags[val.repoName] = val.tags;
}
})
function deleteSelectedTags() {
console.log('Delete selected tags:' + angular.toJson(vm.selectedTags[vm.repoName]) + ' under repo:' + vm.repoName);
vm.toggleInProgress[vm.repoName + '|'] = true;
for(var i in vm.selectedTags[vm.repoName] || []) {
var tag = vm.selectedTags[vm.repoName][i];
if(tag !== '') {
vm.toggleInProgress[vm.repoName + '|' + tag] = true;
DeleteRepositoryService(vm.repoName, tag)
.success(deleteRepositorySuccess)
.error(deleteRepositoryFailed);
}
}
}
function deleteRepositorySuccess(data, status) { function deleteRepositorySuccess(data, status) {
vm.toggleInProgress[vm.repoName + '|'] = false;
vm.toggleInProgress[vm.repoName + '|' + vm.tag] = false; vm.toggleInProgress[vm.repoName + '|' + vm.tag] = false;
vm.retrieve(); vm.retrieve();
$scope.$broadcast('refreshTags', true); $scope.$broadcast('refreshTags', true);
} }
function deleteRepositoryFailed(data, status) { function deleteRepositoryFailed(data, status) {
vm.toggleInProgress[vm.repoName + '|'] = false;
vm.toggleInProgress[vm.repoName + '|' + vm.tag] = false; vm.toggleInProgress[vm.repoName + '|' + vm.tag] = false;
$scope.$emit('modalTitle', $filter('tr')('error')); $scope.$emit('modalTitle', $filter('tr')('error'));

View File

@ -1,6 +1,6 @@
<div id="collapse//vm.associateId//" class="panel-collapse collapse" role="tabpanel" aria-labelledby="heading//vm.associateId//"> <div id="collapse//vm.associateId//" class="panel-collapse collapse" role="tabpanel" aria-labelledby="heading//vm.associateId//">
<div class="panel-body"> <div class="panel-body table-responsive">
<table class="repository-table"> <table class="table" style="margin-bottom: 0;">
<thead> <thead>
<th width="20%"><span class="glyphicon glyphicon-tags"></span> // 'tag' | tr //</th> <th width="20%"><span class="glyphicon glyphicon-tags"></span> // 'tag' | tr //</th>
<th width="15%" style="text-align: center;">// 'image_details' | tr //</th> <th width="15%" style="text-align: center;">// 'image_details' | tr //</th>
@ -14,7 +14,11 @@
<td> <td>
<pull-command repo-name="//vm.repoName//" tag="//tag//"></pull-command> <pull-command repo-name="//vm.repoName//" tag="//tag//"></pull-command>
</td> </td>
<td style="text-align: center;"><a ng-if="vm.roleId == 1" href="javascript:void(0);" ng-click="vm.deleteTag({repoName: vm.repoName, tag: tag})" title="// 'delete_tag' | tr //" loading-progress hide-target="true" toggle-in-progress="vm.toggleInProgress[vm.repoName +'|'+ tag]"><span class="glyphicon glyphicon-trash"></span></a></td> <td style="padding: 2px; padding-left: 6%;">
&nbsp;&nbsp;
<input ng-if="vm.roleId == 1" type="checkbox" ng-checked="vm.selected[vm.repoName][$index]" ng-click="vm.selectOne($index, tag)">
<a ng-show="vm.roleId == 1 && vm.selected[vm.repoName][$index]" href="javascript:void(0);" ng-click="vm.deleteTag({repoName: vm.repoName, tag: tag})" title="// 'delete_tag' | tr //" loading-progress hide-target="true" toggle-in-progress="vm.toggleInProgress[vm.repoName +'|'+ tag]"><span class="glyphicon glyphicon-trash"></span></a>
</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@ -28,8 +28,14 @@
vm.tags = []; vm.tags = [];
vm.retrieve = retrieve; vm.retrieve = retrieve;
vm.selected = []
vm.selected[vm.repoName] = [];
vm.selectedTags = [];
$scope.$watch('vm.repoName', function(current, origin) { $scope.$watch('vm.repoName', function(current, origin) {
if(current) { if(current) {
console.log('vm.repoName triggered tags retrieval.')
vm.retrieve(); vm.retrieve();
} }
}); });
@ -37,11 +43,48 @@
$scope.$on('refreshTags', function(e, val) { $scope.$on('refreshTags', function(e, val) {
if(val) { if(val) {
vm.retrieve(); vm.retrieve();
vm.selectedCount[vm.repoName] = 0;
vm.selected[val.repoName] = [];
vm.selectedTags = [];
}
});
$scope.$watch('vm.selectedCount[vm.repoName]', function(current, previous) {
if(current !== previous) {
console.log('Watching vm.selectedCount:' + current);
$scope.$emit('selectedAll', {'status': (current === vm.tags.length), 'repoName': vm.repoName});
}
});
$scope.$on('gatherSelectedTags' + vm.repoName, function(e, val) {
if(val) {
console.log('RECEIVED gatherSelectedTags:' + val);
gatherSelectedTags();
}
})
$scope.$on('selectAll' + vm.repoName, function(e, val) {
(val.status) ? vm.selectedCount[val.repoName] = vm.tags.length : vm.selectedCount[val.repoName] = 0;
for(var i = 0; i < vm.tags.length; i++) {
vm.selected[val.repoName][i] = val.status;
}
gatherSelectedTags();
console.log('received selectAll:' + angular.toJson(val) + ', vm.selected:' + angular.toJson(vm.selected));
});
$scope.$watch('vm.tags', function(current) {
if(current) {
vm.tags = current;
} }
}); });
vm.deleteTag = deleteTag; vm.deleteTag = deleteTag;
vm.selectedCount = [];
vm.selectedCount[vm.repoName] = 0;
vm.selectOne = selectOne;
function retrieve() { function retrieve() {
ListTagService(vm.repoName) ListTagService(vm.repoName)
.success(getTagSuccess) .success(getTagSuccess)
@ -49,7 +92,6 @@
} }
function getTagSuccess(data) { function getTagSuccess(data) {
vm.tags = data || []; vm.tags = data || [];
vm.tagCount[vm.repoName] = vm.tags.length; vm.tagCount[vm.repoName] = vm.tags.length;
@ -59,6 +101,10 @@
angular.forEach(vm.tags, function(item) { angular.forEach(vm.tags, function(item) {
vm.toggleInProgress[vm.repoName + '|' + item] = false; vm.toggleInProgress[vm.repoName + '|' + item] = false;
}); });
for(var i = 0; i < vm.tags.length; i++) {
vm.selected[vm.repoName][i] = false;
}
} }
function getTagFailed(data) { function getTagFailed(data) {
@ -74,6 +120,28 @@
vm.deleteByTag(); vm.deleteByTag();
} }
function selectOne(index, tagName) {
vm.selected[vm.repoName][index] = !vm.selected[vm.repoName][index];
(vm.selected[vm.repoName][index]) ? ++vm.selectedCount[vm.repoName] : --vm.selectedCount[vm.repoName];
console.log('selectOne, repoName:' + vm.repoName + ', vm.selected:' + vm.selected[vm.repoName][index] + ', index:' + index + ', length:' + vm.selectedCount[vm.repoName]);
gatherSelectedTags();
}
function gatherSelectedTags() {
vm.selectedTags[vm.repoName] = [];
for(var i = 0; i < vm.tags.length; i++) {
(vm.selected[vm.repoName][i]) ? vm.selectedTags[vm.repoName][i] = vm.tags[i] : vm.selectedTags[vm.repoName][i] = '';
}
var tagsToDelete = [];
for(var i in vm.selectedTags[vm.repoName]) {
var tag = vm.selectedTags[vm.repoName][i];
if(tag !== '') {
tagsToDelete.push(tag);
}
}
$scope.$emit('selectedTags', {'repoName': vm.repoName, 'tags': tagsToDelete});
}
} }
function listTag() { function listTag() {

View File

@ -1,7 +1,5 @@
<form class="form-inline"> <form class="form-inline">
<div class="form-group"> <div class="form-group" style="width: 100%;">
<div class="input-group"> <input type="text" class="form-control form-control-static" style="padding-left: 10px; width: 100%;" value="docker pull //vm.harborRegUrl////vm.repoName//://vm.tag//" readonly="readonly">
<input type="text" class="form-control-static" style="padding-left: 10px;" value="docker pull //vm.harborRegUrl////vm.repoName//://vm.tag//" readonly="readonly" size="60">
</div>
</div> </div>
</form> </form>

View File

@ -142,6 +142,7 @@ var locale_messages = {
'<br/>Delete repository "$0" now?', '<br/>Delete repository "$0" now?',
'alert_delete_tag_title': 'Confirm Deletion', 'alert_delete_tag_title': 'Confirm Deletion',
'alert_delete_tag': 'Note: All tags under this repository will be deleted if they are pointing to this image.<br/><br/>Delete tag "$0" now?', 'alert_delete_tag': 'Note: All tags under this repository will be deleted if they are pointing to this image.<br/><br/>Delete tag "$0" now?',
'alert_delete_selected_tag': 'Note: All selected tags under this repository will be deleted if they are pointing to this image.<br/><br/>Delete selected tags now?',
'close': 'Close', 'close': 'Close',
'ok': 'OK', 'ok': 'OK',
'welcome': 'Welcome to Harbor!', 'welcome': 'Welcome to Harbor!',
@ -217,6 +218,7 @@ var locale_messages = {
'select_all': 'Select All', 'select_all': 'Select All',
'delete_tag': 'Delete Tag', 'delete_tag': 'Delete Tag',
'delete_repo': 'Delete Repo', 'delete_repo': 'Delete Repo',
'delete_selected_tag': 'Delete Selected Tag(s)',
'download_log': 'View Logs', 'download_log': 'View Logs',
'edit': 'Edit', 'edit': 'Edit',
'delete': 'Delete', 'delete': 'Delete',

View File

@ -142,6 +142,7 @@ var locale_messages = {
'<br/>是否删除镜像仓库 "$0" ?', '<br/>是否删除镜像仓库 "$0" ?',
'alert_delete_tag_title': '确认删除', 'alert_delete_tag_title': '确认删除',
'alert_delete_tag': '注意:此镜像仓库下所有指向该镜像的标签将会被删除。<br/><br/>删除镜像标签 "$0" ?', 'alert_delete_tag': '注意:此镜像仓库下所有指向该镜像的标签将会被删除。<br/><br/>删除镜像标签 "$0" ?',
'alert_delete_selected_tag': '注意:此镜像仓库下选中的指向该镜像的标签将会被删除。<br/><br/>删除选中的镜像标签?',
'close': '关闭', 'close': '关闭',
'ok': '确认', 'ok': '确认',
'welcome': '欢迎使用Harbor!', 'welcome': '欢迎使用Harbor!',
@ -217,6 +218,7 @@ var locale_messages = {
'select_all': '全选', 'select_all': '全选',
'delete_tag': '删除镜像标签', 'delete_tag': '删除镜像标签',
'delete_repo': '删除镜像仓库', 'delete_repo': '删除镜像仓库',
'delete_selected_tag': '删除选中镜像标签',
'download_log': '查看日志', 'download_log': '查看日志',
'edit': '修改', 'edit': '修改',
'delete': '删除', 'delete': '删除',