2015-03-12 00:46:50 +00:00
|
|
|
/**
|
|
|
|
* 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: {
|
2015-03-12 19:22:47 +00:00
|
|
|
'repository': '=repository',
|
|
|
|
'selectedTags': '=selectedTags',
|
2015-03-18 18:47:53 +00:00
|
|
|
|
|
|
|
'imagesResource': '=imagesResource',
|
|
|
|
'images': '=images',
|
|
|
|
|
2015-03-12 19:22:47 +00:00
|
|
|
'isEnabled': '=isEnabled'
|
2015-03-12 00:46:50 +00:00
|
|
|
},
|
2015-03-12 19:22:47 +00:00
|
|
|
controller: function($scope, $element, $timeout, ApiService, UtilService, ImageMetadataService) {
|
2015-04-27 21:36:31 +00:00
|
|
|
$scope.tagNames = [];
|
2015-03-12 00:46:50 +00:00
|
|
|
|
2015-07-31 20:31:29 +00:00
|
|
|
$scope.$watch('selectedTags', function(selectedTags) {
|
|
|
|
if (!selectedTags) { return; }
|
|
|
|
$scope.selectedTagsSlice = selectedTags.slice(0, 10);
|
|
|
|
});
|
|
|
|
|
2015-03-12 00:46:50 +00:00
|
|
|
var update = function() {
|
2015-04-27 21:36:31 +00:00
|
|
|
if (!$scope.repository || !$scope.isEnabled) { return; }
|
2015-03-12 00:46:50 +00:00
|
|
|
|
2015-04-27 21:36:31 +00:00
|
|
|
$scope.tagNames = Object.keys($scope.repository.tags);
|
2015-03-12 00:46:50 +00:00
|
|
|
$scope.currentImage = null;
|
2015-03-12 19:22:47 +00:00
|
|
|
$scope.currentTag = null;
|
2015-03-12 00:46:50 +00:00
|
|
|
|
2015-04-27 21:36:31 +00:00
|
|
|
if ($scope.tracker) {
|
|
|
|
refreshTree();
|
|
|
|
} else {
|
2015-03-18 18:47:53 +00:00
|
|
|
updateImages();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
var updateImages = function() {
|
2015-04-27 21:36:31 +00:00
|
|
|
if (!$scope.repository || !$scope.images || !$scope.isEnabled) { return; }
|
2015-03-18 18:47:53 +00:00
|
|
|
|
|
|
|
$scope.tracker = new RepositoryImageTracker($scope.repository, $scope.images);
|
|
|
|
|
2015-07-31 20:31:29 +00:00
|
|
|
if ($scope.selectedTagsSlice && $scope.selectedTagsSlice.length) {
|
2015-03-18 18:47:53 +00:00
|
|
|
refreshTree();
|
2015-03-12 00:46:50 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-07-31 20:31:29 +00:00
|
|
|
$scope.$watch('selectedTagsSlice', update)
|
2015-03-12 00:46:50 +00:00
|
|
|
$scope.$watch('repository', update);
|
2015-04-27 21:36:31 +00:00
|
|
|
$scope.$watch('isEnabled', update);
|
|
|
|
|
2015-03-18 18:47:53 +00:00
|
|
|
$scope.$watch('images', updateImages);
|
2015-03-12 00:46:50 +00:00
|
|
|
|
2015-04-27 21:36:31 +00:00
|
|
|
$scope.updateState = function() {
|
|
|
|
update();
|
|
|
|
};
|
2015-03-12 19:22:47 +00:00
|
|
|
|
2015-03-12 00:46:50 +00:00
|
|
|
var refreshTree = function() {
|
2015-04-27 21:36:31 +00:00
|
|
|
if (!$scope.repository || !$scope.images || !$scope.isEnabled) { return; }
|
2015-07-31 20:31:29 +00:00
|
|
|
if ($scope.selectedTagsSlice.length < 1) { return; }
|
2015-03-12 00:46:50 +00:00
|
|
|
|
|
|
|
$('#image-history-container').empty();
|
|
|
|
|
|
|
|
var tree = new ImageHistoryTree(
|
|
|
|
$scope.repository.namespace,
|
|
|
|
$scope.repository.name,
|
|
|
|
$scope.images,
|
|
|
|
UtilService.getFirstMarkdownLineAsText,
|
|
|
|
$scope.getTimeSince,
|
|
|
|
ImageMetadataService.getEscapedFormattedCommand,
|
|
|
|
function(tag) {
|
2015-07-31 20:31:29 +00:00
|
|
|
return $.inArray(tag, $scope.selectedTagsSlice) >= 0;
|
2015-03-12 00:46:50 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
$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();
|
2015-07-31 20:31:29 +00:00
|
|
|
$scope.setTag($scope.selectedTagsSlice[0]);
|
2015-03-12 00:46:50 +00:00
|
|
|
}, 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); });
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
$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.currentImage = null;
|
|
|
|
$scope.currentTag = null;
|
|
|
|
});
|
|
|
|
|
|
|
|
data.added.map(function(tag) {
|
|
|
|
$scope.selectedTags.push(tag);
|
|
|
|
$scope.currentTag = tag;
|
|
|
|
});
|
2015-03-12 19:22:47 +00:00
|
|
|
|
|
|
|
refreshTree();
|
2015-03-12 00:46:50 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
return directiveDefinitionObject;
|
|
|
|
});
|
|
|
|
|