Get full actions working in the repo changes tab
This commit is contained in:
parent
89e71b75dd
commit
a18148b058
9 changed files with 490 additions and 54 deletions
221
static/js/directives/repo-view/repo-panel-changes.js
Normal file
221
static/js/directives/repo-view/repo-panel-changes.js
Normal file
|
@ -0,0 +1,221 @@
|
||||||
|
/**
|
||||||
|
* An element which displays the changes visualization panel for a repository view.
|
||||||
|
*/
|
||||||
|
angular.module('quay').directive('repoPanelChanges', function () {
|
||||||
|
var RepositoryImageTracker = function(repository, images) {
|
||||||
|
this.repository = repository;
|
||||||
|
this.images = images;
|
||||||
|
|
||||||
|
// Build a map of image ID -> image.
|
||||||
|
var imageIDMap = {};
|
||||||
|
this.images.map(function(image) {
|
||||||
|
imageIDMap[image.id] = image;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.imageMap_ = imageIDMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
RepositoryImageTracker.prototype.imageLink = function(image) {
|
||||||
|
return '/repository/' + this.repository.namespace + '/' +
|
||||||
|
this.repository.name + '/image/' + image;
|
||||||
|
};
|
||||||
|
|
||||||
|
RepositoryImageTracker.prototype.getImageForTag = function(tag) {
|
||||||
|
var tagData = this.lookupTag(tag);
|
||||||
|
if (!tagData) { return null; }
|
||||||
|
|
||||||
|
return this.imageMap_[tagData.image_id];
|
||||||
|
};
|
||||||
|
|
||||||
|
RepositoryImageTracker.prototype.lookupTag = function(tag) {
|
||||||
|
return this.repository.tags[tag];
|
||||||
|
};
|
||||||
|
|
||||||
|
RepositoryImageTracker.prototype.lookupImage = function(image) {
|
||||||
|
return this.imageMap_[image];
|
||||||
|
};
|
||||||
|
|
||||||
|
RepositoryImageTracker.prototype.forAllTagImages = function(tag, callback) {
|
||||||
|
var tagData = this.lookupTag(tag);
|
||||||
|
if (!tagData) { return; }
|
||||||
|
|
||||||
|
var tagImage = this.imageMap_[tagData.image_id];
|
||||||
|
if (!tagImage) { return; }
|
||||||
|
|
||||||
|
// Callback the tag's image itself.
|
||||||
|
callback(tagImage);
|
||||||
|
|
||||||
|
// Callback any parent images.
|
||||||
|
if (!tagImage.ancestors) { return; }
|
||||||
|
|
||||||
|
var ancestors = tagImage.ancestors.split('/');
|
||||||
|
for (var i = 0; i < ancestors.length; ++i) {
|
||||||
|
var image = this.imageMap_[ancestors[i]];
|
||||||
|
if (image) {
|
||||||
|
callback(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
RepositoryImageTracker.prototype.getTotalSize = function(tag) {
|
||||||
|
var size = 0;
|
||||||
|
this.forAllTagImages(tag, function(image) {
|
||||||
|
size += image.size;
|
||||||
|
});
|
||||||
|
return size;
|
||||||
|
};
|
||||||
|
|
||||||
|
RepositoryImageTracker.prototype.getImagesForTagBySize = function(tag) {
|
||||||
|
var images = [];
|
||||||
|
this.forAllTagImages(tag, function(image) {
|
||||||
|
images.push(image);
|
||||||
|
});
|
||||||
|
|
||||||
|
images.sort(function(a, b) {
|
||||||
|
return b.size - a.size;
|
||||||
|
});
|
||||||
|
|
||||||
|
return images;
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
var directiveDefinitionObject = {
|
||||||
|
priority: 0,
|
||||||
|
templateUrl: '/static/directives/repo-view/repo-panel-changes.html',
|
||||||
|
replace: false,
|
||||||
|
transclude: false,
|
||||||
|
restrict: 'C',
|
||||||
|
scope: {
|
||||||
|
'repository': '=repository'
|
||||||
|
},
|
||||||
|
controller: function($scope, $element, $location, $timeout, ApiService, UtilService, ImageMetadataService) {
|
||||||
|
|
||||||
|
var update = function() {
|
||||||
|
if (!$scope.repository) { return; }
|
||||||
|
|
||||||
|
var tagString = $location.search()['tags'] || '';
|
||||||
|
if (!tagString) {
|
||||||
|
$scope.selectedTags = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.currentImage = null;
|
||||||
|
$scope.currentImage = null;
|
||||||
|
$scope.selectedTags = tagString.split(',');
|
||||||
|
|
||||||
|
if (!$scope.imageResource) {
|
||||||
|
loadImages();
|
||||||
|
} else {
|
||||||
|
refreshTree();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.$on('$routeUpdate', update);
|
||||||
|
$scope.$watch('repository', update);
|
||||||
|
|
||||||
|
var refreshTree = function() {
|
||||||
|
if (!$scope.repository || !$scope.images) { return; }
|
||||||
|
|
||||||
|
$('#image-history-container').empty();
|
||||||
|
|
||||||
|
var tree = new ImageHistoryTree(
|
||||||
|
$scope.repository.namespace,
|
||||||
|
$scope.repository.name,
|
||||||
|
$scope.images,
|
||||||
|
UtilService.getFirstMarkdownLineAsText,
|
||||||
|
$scope.getTimeSince,
|
||||||
|
ImageMetadataService.getEscapedFormattedCommand,
|
||||||
|
function(tag) {
|
||||||
|
return $.inArray(tag, $scope.selectedTags) >= 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
$scope.tree = tree.draw('image-history-container');
|
||||||
|
if ($scope.tree) {
|
||||||
|
// Give enough time for the UI to be drawn before we resize the tree.
|
||||||
|
$timeout(function() {
|
||||||
|
$scope.tree.notifyResized();
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
// Listen for changes to the selected tag and image in the tree.
|
||||||
|
$($scope.tree).bind('tagChanged', function(e) {
|
||||||
|
$scope.$apply(function() { $scope.setTag(e.tag); });
|
||||||
|
});
|
||||||
|
|
||||||
|
$($scope.tree).bind('imageChanged', function(e) {
|
||||||
|
$scope.$apply(function() { $scope.setImage(e.image.id); });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var loadImages = function(opt_callback) {
|
||||||
|
var params = {
|
||||||
|
'repository': $scope.repository.namespace + '/' + $scope.repository.name
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.imagesResource = ApiService.listRepositoryImagesAsResource(params).get(function(resp) {
|
||||||
|
$scope.images = resp.images;
|
||||||
|
$scope.tracker = new RepositoryImageTracker($scope.repository, $scope.images);
|
||||||
|
|
||||||
|
$scope.selectedTags = $.grep($scope.selectedTags, function(tag) {
|
||||||
|
return !!$scope.tracker.lookupTag(tag);
|
||||||
|
});
|
||||||
|
|
||||||
|
if ($scope.selectedTags && $scope.selectedTags.length) {
|
||||||
|
refreshTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
opt_callback && opt_callback();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.setImage = function(image_id) {
|
||||||
|
$scope.currentTag = null;
|
||||||
|
$scope.currentImage = image_id;
|
||||||
|
$scope.tree.setImage(image_id);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.setTag = function(tag) {
|
||||||
|
$scope.currentTag = tag;
|
||||||
|
$scope.currentImage = null;
|
||||||
|
$scope.tree.setTag(tag);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.parseDate = function(dateString) {
|
||||||
|
return Date.parse(dateString);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.getTimeSince = function(createdTime) {
|
||||||
|
return moment($scope.parseDate(createdTime)).fromNow();
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.handleTagChanged = function(data) {
|
||||||
|
$scope.tracker = new RepositoryImageTracker($scope.repository, $scope.images);
|
||||||
|
|
||||||
|
data.removed.map(function(tag) {
|
||||||
|
$scope.selectedTags = $.grep($scope.selectedTags, function(cTag) {
|
||||||
|
return cTag != tag;
|
||||||
|
});
|
||||||
|
|
||||||
|
if ($scope.selectedTags.length) {
|
||||||
|
$location.search('tags', $scope.selectedTags.join(','));
|
||||||
|
} else {
|
||||||
|
$location.search('tags', null);
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.currentImage = null;
|
||||||
|
$scope.currentTag = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
data.added.map(function(tag) {
|
||||||
|
$scope.selectedTags.push(tag);
|
||||||
|
$location.search('tags', $scope.selectedTags.join(','));
|
||||||
|
|
||||||
|
$scope.currentTag = tag;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return directiveDefinitionObject;
|
||||||
|
});
|
||||||
|
|
|
@ -22,6 +22,7 @@ angular.module('quay').directive('repoPanelTags', function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.iterationState = {};
|
$scope.iterationState = {};
|
||||||
|
$scope.tagActionHandler = null;
|
||||||
|
|
||||||
var loadImages = function() {
|
var loadImages = function() {
|
||||||
var params = {
|
var params = {
|
||||||
|
@ -140,57 +141,11 @@ angular.module('quay').directive('repoPanelTags', function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.askDeleteTag = function(tag) {
|
$scope.askDeleteTag = function(tag) {
|
||||||
$scope.deleteTagInfo = {
|
$scope.tagActionHandler.askDeleteTag(tag);
|
||||||
'tag': tag
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.askDeleteMultipleTags = function(tags) {
|
$scope.askDeleteMultipleTags = function(tags) {
|
||||||
$scope.deleteMultipleTagsInfo = {
|
$scope.tagActionHandler.askDeleteMultipleTags(tags);
|
||||||
'tags': tags
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.deleteMultipleTags = function(tags, callback) {
|
|
||||||
var count = tags.length;
|
|
||||||
var perform = function(index) {
|
|
||||||
if (index >= count) {
|
|
||||||
callback(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var tag_info = tags[index];
|
|
||||||
$scope.deleteTag(tag_info.name, function(result) {
|
|
||||||
if (!result) {
|
|
||||||
callback(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
perform(index + 1);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
perform(0);
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.deleteTag = function(tag, callback) {
|
|
||||||
if (!$scope.repository.can_admin) { return; }
|
|
||||||
|
|
||||||
var params = {
|
|
||||||
'repository': $scope.repository.namespace + '/' + $scope.repository.name,
|
|
||||||
'tag': tag
|
|
||||||
};
|
|
||||||
|
|
||||||
var errorHandler = ApiService.errorDisplay('Cannot delete tag', callback);
|
|
||||||
ApiService.deleteFullTag(null, params).then(function() {
|
|
||||||
callback(true);
|
|
||||||
$scope.tags = $.grep($scope.tags, function(tagInfo) {
|
|
||||||
return tagInfo.name != tag;
|
|
||||||
});
|
|
||||||
|
|
||||||
$scope.checkedTags = UIService.createCheckStateController($scope.tags);
|
|
||||||
$scope.repositoryUpdated({});
|
|
||||||
}, errorHandler);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.orderBy = function(predicate) {
|
$scope.orderBy = function(predicate) {
|
||||||
|
@ -219,6 +174,12 @@ angular.module('quay').directive('repoPanelTags', function () {
|
||||||
$scope.imageIDFilter = function(image_id, tag) {
|
$scope.imageIDFilter = function(image_id, tag) {
|
||||||
return tag.image_id == image_id;
|
return tag.image_id == image_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.getCheckedTagsString = function(checked) {
|
||||||
|
return checked.map(function(tag_info) {
|
||||||
|
return tag_info.name;
|
||||||
|
}).join(',');
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return directiveDefinitionObject;
|
return directiveDefinitionObject;
|
||||||
|
|
34
static/js/directives/ui/image-changes-view.js
Normal file
34
static/js/directives/ui/image-changes-view.js
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/**
|
||||||
|
* An element which loads and displays UI representing the changes made in an image.
|
||||||
|
*/
|
||||||
|
angular.module('quay').directive('imageChangesView', function () {
|
||||||
|
var directiveDefinitionObject = {
|
||||||
|
priority: 0,
|
||||||
|
templateUrl: '/static/directives/image-changes-view.html',
|
||||||
|
replace: false,
|
||||||
|
transclude: false,
|
||||||
|
restrict: 'C',
|
||||||
|
scope: {
|
||||||
|
'repository': '=repository',
|
||||||
|
'image': '=image',
|
||||||
|
'hasChanges': '=hasChanges'
|
||||||
|
},
|
||||||
|
controller: function($scope, $element, ApiService) {
|
||||||
|
$scope.$watch('image', function() {
|
||||||
|
if (!$scope.image || !$scope.repository) { return; }
|
||||||
|
|
||||||
|
var params = {
|
||||||
|
'repository': $scope.repository.namespace + '/' + $scope.repository.name,
|
||||||
|
'image_id': $scope.image
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.hasChanges = true;
|
||||||
|
$scope.imageChangesResource = ApiService.getImageChangesAsResource(params).get(function(resp) {
|
||||||
|
$scope.changeData = resp;
|
||||||
|
$scope.hasChanges = resp.added.length || resp.removed.length || resp.changed.length;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return directiveDefinitionObject;
|
||||||
|
});
|
32
static/js/directives/ui/image-info-sidebar.js
Normal file
32
static/js/directives/ui/image-info-sidebar.js
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/**
|
||||||
|
* An element which displays sidebar information for a image. Primarily used in the repo view.
|
||||||
|
*/
|
||||||
|
angular.module('quay').directive('imageInfoSidebar', function () {
|
||||||
|
var directiveDefinitionObject = {
|
||||||
|
priority: 0,
|
||||||
|
templateUrl: '/static/directives/image-info-sidebar.html',
|
||||||
|
replace: false,
|
||||||
|
transclude: true,
|
||||||
|
restrict: 'C',
|
||||||
|
scope: {
|
||||||
|
'tracker': '=tracker',
|
||||||
|
'image': '=image',
|
||||||
|
|
||||||
|
'tagSelected': '&tagSelected',
|
||||||
|
'addTagRequested': '&addTagRequested'
|
||||||
|
},
|
||||||
|
controller: function($scope, $element, ImageMetadataService) {
|
||||||
|
$scope.$watch('image', function(image) {
|
||||||
|
if (!image || !$scope.tracker) { return; }
|
||||||
|
$scope.imageData = $scope.tracker.lookupImage(image);
|
||||||
|
});
|
||||||
|
|
||||||
|
$scope.parseDate = function(dateString) {
|
||||||
|
return Date.parse(dateString);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.getFormattedCommand = ImageMetadataService.getFormattedCommand;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return directiveDefinitionObject;
|
||||||
|
});
|
|
@ -21,6 +21,10 @@ angular.module('quay').directive('resourceView', function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
var resources = $scope.resources || [$scope.resource];
|
var resources = $scope.resources || [$scope.resource];
|
||||||
|
if (!resources.length) {
|
||||||
|
return 'loading';
|
||||||
|
}
|
||||||
|
|
||||||
for (var i = 0; i < resources.length; ++i) {
|
for (var i = 0; i < resources.length; ++i) {
|
||||||
var current = resources[i];
|
var current = resources[i];
|
||||||
if (current.loading) {
|
if (current.loading) {
|
||||||
|
|
28
static/js/directives/ui/tag-info-sidebar.js
Normal file
28
static/js/directives/ui/tag-info-sidebar.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/**
|
||||||
|
* An element which displays sidebar information for a tag. Primarily used in the repo view.
|
||||||
|
*/
|
||||||
|
angular.module('quay').directive('tagInfoSidebar', function () {
|
||||||
|
var directiveDefinitionObject = {
|
||||||
|
priority: 0,
|
||||||
|
templateUrl: '/static/directives/tag-info-sidebar.html',
|
||||||
|
replace: false,
|
||||||
|
transclude: true,
|
||||||
|
restrict: 'C',
|
||||||
|
scope: {
|
||||||
|
'tracker': '=tracker',
|
||||||
|
'tag': '=tag',
|
||||||
|
|
||||||
|
'imageSelected': '&imageSelected',
|
||||||
|
'deleteTagRequested': '&deleteTagRequested'
|
||||||
|
},
|
||||||
|
controller: function($scope, $element) {
|
||||||
|
$scope.$watch('tag', function(tag) {
|
||||||
|
if (!tag || !$scope.tracker) { return; }
|
||||||
|
|
||||||
|
$scope.tagImage = $scope.tracker.getImageForTag(tag);
|
||||||
|
$scope.tagData = $scope.tracker.lookupTag(tag);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return directiveDefinitionObject;
|
||||||
|
});
|
142
static/js/directives/ui/tag-operations-dialog.js
Normal file
142
static/js/directives/ui/tag-operations-dialog.js
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
/**
|
||||||
|
* An element which adds a series of dialogs for performing operations for tags (adding, moving
|
||||||
|
* deleting).
|
||||||
|
*/
|
||||||
|
angular.module('quay').directive('tagOperationsDialog', function () {
|
||||||
|
var directiveDefinitionObject = {
|
||||||
|
priority: 0,
|
||||||
|
templateUrl: '/static/directives/tag-operations-dialog.html',
|
||||||
|
replace: false,
|
||||||
|
transclude: false,
|
||||||
|
restrict: 'C',
|
||||||
|
scope: {
|
||||||
|
'repository': '=repository',
|
||||||
|
'images': '=images',
|
||||||
|
'actionHandler': '=actionHandler',
|
||||||
|
|
||||||
|
'tagChanged': '&tagChanged'
|
||||||
|
},
|
||||||
|
controller: function($scope, $element, $timeout, ApiService) {
|
||||||
|
$scope.addingTag = false;
|
||||||
|
|
||||||
|
var markChanged = function(added, removed) {
|
||||||
|
// Reload the repository and the images.
|
||||||
|
$scope.repository.get().then(function(resp) {
|
||||||
|
$scope.repository = resp;
|
||||||
|
|
||||||
|
var params = {
|
||||||
|
'repository': resp.namespace + '/' + resp.name
|
||||||
|
};
|
||||||
|
|
||||||
|
ApiService.listRepositoryImages(null, params).then(function(resp) {
|
||||||
|
$scope.images = resp.images;
|
||||||
|
$scope.tagChanged({
|
||||||
|
'data': { 'added': added, 'removed': removed }
|
||||||
|
});
|
||||||
|
})
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.isAnotherImageTag = function(image, tag) {
|
||||||
|
if (!$scope.repository || !$scope.images) { return; }
|
||||||
|
|
||||||
|
var found = $scope.repository.tags[tag];
|
||||||
|
if (found == null) { return false; }
|
||||||
|
return found.image_id != image;
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.isOwnedTag = function(image, tag) {
|
||||||
|
if (!$scope.repository || !$scope.images) { return; }
|
||||||
|
|
||||||
|
var found = $scope.repository.tags[tag];
|
||||||
|
if (found == null) { return false; }
|
||||||
|
return found.image_id == image;
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.createOrMoveTag = function(image, tag) {
|
||||||
|
$scope.addingTag = true;
|
||||||
|
|
||||||
|
var params = {
|
||||||
|
'repository': $scope.repository.namespace + '/' + $scope.repository.name,
|
||||||
|
'tag': tag
|
||||||
|
};
|
||||||
|
|
||||||
|
var data = {
|
||||||
|
'image': image
|
||||||
|
};
|
||||||
|
|
||||||
|
var errorHandler = ApiService.errorDisplay('Cannot create or move tag', function(resp) {
|
||||||
|
$element.find('#createOrMoveTagModal').modal('hide');
|
||||||
|
});
|
||||||
|
|
||||||
|
ApiService.changeTagImage(data, params).then(function(resp) {
|
||||||
|
$element.find('#createOrMoveTagModal').modal('hide');
|
||||||
|
$scope.addingTag = false;
|
||||||
|
|
||||||
|
markChanged([tag], []);
|
||||||
|
}, errorHandler);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.deleteMultipleTags = function(tags, callback) {
|
||||||
|
var count = tags.length;
|
||||||
|
var perform = function(index) {
|
||||||
|
if (index >= count) {
|
||||||
|
callback(true);
|
||||||
|
markChanged([], tags);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tag_info = tags[index];
|
||||||
|
$scope.deleteTag(tag_info.name, function(result) {
|
||||||
|
if (!result) {
|
||||||
|
callback(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
perform(index + 1);
|
||||||
|
}, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
perform(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.deleteTag = function(tag, callback, opt_skipmarking) {
|
||||||
|
if (!$scope.repository.can_admin) { return; }
|
||||||
|
|
||||||
|
var params = {
|
||||||
|
'repository': $scope.repository.namespace + '/' + $scope.repository.name,
|
||||||
|
'tag': tag
|
||||||
|
};
|
||||||
|
|
||||||
|
var errorHandler = ApiService.errorDisplay('Cannot delete tag', callback);
|
||||||
|
ApiService.deleteFullTag(null, params).then(function() {
|
||||||
|
callback(true);
|
||||||
|
!opt_skipmarking && markChanged([], [tag]);
|
||||||
|
}, errorHandler);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.actionHandler = {
|
||||||
|
'askDeleteTag': function(tag) {
|
||||||
|
$scope.deleteTagInfo = {
|
||||||
|
'tag': tag
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
'askDeleteMultipleTags': function(tags) {
|
||||||
|
$scope.deleteMultipleTagsInfo = {
|
||||||
|
'tags': tags
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
'askAddTag': function(image) {
|
||||||
|
$scope.tagToCreate = '';
|
||||||
|
$scope.toTagImage = image;
|
||||||
|
$scope.addingTag = false;
|
||||||
|
$scope.addTagForm.$setPristine();
|
||||||
|
$element.find('#createOrMoveTagModal').modal('show');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return directiveDefinitionObject;
|
||||||
|
});
|
|
@ -31,7 +31,9 @@ var DEPTH_WIDTH = 140;
|
||||||
/**
|
/**
|
||||||
* Based off of http://mbostock.github.io/d3/talk/20111018/tree.html by Mike Bostock (@mbostock)
|
* Based off of http://mbostock.github.io/d3/talk/20111018/tree.html by Mike Bostock (@mbostock)
|
||||||
*/
|
*/
|
||||||
function ImageHistoryTree(namespace, name, images, formatComment, formatTime, formatCommand) {
|
function ImageHistoryTree(namespace, name, images, formatComment, formatTime, formatCommand,
|
||||||
|
opt_tagFilter) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The namespace of the repo.
|
* The namespace of the repo.
|
||||||
*/
|
*/
|
||||||
|
@ -62,6 +64,11 @@ function ImageHistoryTree(namespace, name, images, formatComment, formatTime, fo
|
||||||
*/
|
*/
|
||||||
this.formatCommand_ = formatCommand;
|
this.formatCommand_ = formatCommand;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method for filtering the tags and image paths displayed in the tree.
|
||||||
|
*/
|
||||||
|
this.tagFilter_ = opt_tagFilter || function() { return true; };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current tag (if any).
|
* The current tag (if any).
|
||||||
*/
|
*/
|
||||||
|
@ -153,7 +160,7 @@ ImageHistoryTree.prototype.updateDimensions_ = function() {
|
||||||
$('#' + container).removeOverscroll();
|
$('#' + container).removeOverscroll();
|
||||||
var viewportHeight = $(window).height();
|
var viewportHeight = $(window).height();
|
||||||
var boundingBox = document.getElementById(container).getBoundingClientRect();
|
var boundingBox = document.getElementById(container).getBoundingClientRect();
|
||||||
document.getElementById(container).style.maxHeight = (viewportHeight - boundingBox.top - 150) + 'px';
|
document.getElementById(container).style.maxHeight = (viewportHeight - boundingBox.top - 100) + 'px';
|
||||||
|
|
||||||
this.setupOverscroll_();
|
this.setupOverscroll_();
|
||||||
|
|
||||||
|
@ -526,7 +533,14 @@ ImageHistoryTree.prototype.pruneUnreferenced_ = function(node) {
|
||||||
return node.children.length == 0;
|
return node.children.length == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (node.children.length == 0 && node.tags.length == 0);
|
var tags = [];
|
||||||
|
for (var i = 0; i < node.tags.length; ++i) {
|
||||||
|
if (this.tagFilter_(node.tags[i])) {
|
||||||
|
tags.push(node.tags[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (node.children.length == 0 && tags.length == 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -554,7 +568,7 @@ ImageHistoryTree.prototype.collapseNodes_ = function(node) {
|
||||||
var current = node;
|
var current = node;
|
||||||
var previous = node;
|
var previous = node;
|
||||||
var encountered = [];
|
var encountered = [];
|
||||||
while (current.children.length == 1) {
|
while (current.children.length == 1 && current.tags.length == 0) {
|
||||||
encountered.push(current);
|
encountered.push(current);
|
||||||
previous = current;
|
previous = current;
|
||||||
current = current.children[0];
|
current = current.children[0];
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
<i class="fa fa-tasks"></i>
|
<i class="fa fa-tasks"></i>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class="cor-tab" tab-title="Changes" tab-target="#changes">
|
<span class="cor-tab" tab-title="Visualize" tab-target="#changes">
|
||||||
<i class="fa fa-code-fork"></i>
|
<i class="fa fa-code-fork"></i>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@
|
||||||
|
|
||||||
<!-- Changes -->
|
<!-- Changes -->
|
||||||
<div id="changes" class="tab-pane">
|
<div id="changes" class="tab-pane">
|
||||||
changes
|
<div class="repo-panel-changes" repository="repository"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Usage Logs -->
|
<!-- Usage Logs -->
|
||||||
|
|
Reference in a new issue