Get the tabs working and the UI for the image history. Note that the model changes for the image history are WRONG and need to be fixed

This commit is contained in:
Joseph Schorr 2013-09-27 17:01:45 -04:00
parent 94cba8a0bc
commit bf926aceee
5 changed files with 89 additions and 16 deletions

View file

@ -148,6 +148,13 @@ def get_repository_images(namespace_name, repository_name):
return joined.where(Repository.name == repository_name, return joined.where(Repository.name == repository_name,
Repository.namespace == namespace_name) Repository.namespace == namespace_name)
def get_tag_images(namespace_name, repository_name, tag_name):
joined = Image.select().join(RepositoryTag).join(Repository)
fetched = list(joined.where(Repository.name == repository_name,
Repository.namespace == namespace_name,
RepositoryTag.name == tag_name))
return fetched
def list_repository_tags(namespace_name, repository_name): def list_repository_tags(namespace_name, repository_name):
select = RepositoryTag.select(RepositoryTag, Image) select = RepositoryTag.select(RepositoryTag, Image)
@ -158,11 +165,7 @@ def list_repository_tags(namespace_name, repository_name):
def get_tag_image(namespace_name, repository_name, tag_name): def get_tag_image(namespace_name, repository_name, tag_name):
joined = Image.select().join(RepositoryTag).join(Repository) fetched = get_tag_images(namespace_name, repository_name, tag_name)
fetched = list(joined.where(Repository.name == repository_name,
Repository.namespace == namespace_name,
RepositoryTag.name == tag_name))
if not fetched: if not fetched:
raise DataModelException('Unable to find image for tag.') raise DataModelException('Unable to find image for tag.')

View file

@ -79,11 +79,6 @@ def update_repo_api(namespace, repository):
abort(404) abort(404)
@app.route('/api/repository/<path:repository>', methods=['GET'])
@login_required
@parse_repository_name
def get_repo_api(namespace, repository):
logger.debug('Get repo: %s/%s' % (namespace, repository))
def image_view(image): def image_view(image):
return { return {
'id': image.image_id, 'id': image.image_id,
@ -91,6 +86,13 @@ def get_repo_api(namespace, repository):
'comment': image.comment, 'comment': image.comment,
} }
@app.route('/api/repository/<path:repository>', methods=['GET'])
@login_required
@parse_repository_name
def get_repo_api(namespace, repository):
logger.debug('Get repo: %s/%s' % (namespace, repository))
def tag_view(tag): def tag_view(tag):
image = model.get_tag_image(namespace, repository, tag.name) image = model.get_tag_image(namespace, repository, tag.name)
if not image: if not image:
@ -128,6 +130,21 @@ def role_view(repo_perm_obj):
} }
@app.route('/api/repository/<path:repository>/tag/<tag>/images', methods=['GET'])
@login_required
@parse_repository_name
def list_tag_images(namespace, repository, tag):
permission = ReadRepositoryPermission(namespace, repository)
if permission.can():
images = model.get_tag_images(namespace, repository, tag)
return jsonify({
'images': [image_view(image) for image in images]
})
abort(403) # Permission denied
@app.route('/api/repository/<path:repository>/permissions/', methods=['GET']) @app.route('/api/repository/<path:repository>/permissions/', methods=['GET'])
@login_required @login_required
@parse_repository_name @parse_repository_name

View file

@ -182,11 +182,15 @@ p.editable:hover i {
min-width: 300px; min-width: 300px;
} }
.repo-admin thead td { .repo thead td {
padding: 4px; padding: 4px;
color: #999; color: #999;
} }
.repo-admin td { .repo td {
padding: 6px; padding: 6px;
} }
.repo .images {
margin: 10px;
}

View file

@ -16,8 +16,24 @@ function LandingCtrl($scope) {
} }
function RepoCtrl($scope, Restangular, $routeParams, $rootScope) { function RepoCtrl($scope, Restangular, $routeParams, $rootScope) {
var tabs = ['current-image', 'image-history'];
$rootScope.title = 'Loading...'; $rootScope.title = 'Loading...';
$scope.showTab = function(tabName) {
for (var i = 0; i < tabs.length; ++i) {
$('#' + tabs[i]).hide();
$('#' + tabs[i] + '-tab').removeClass('active');
}
$('#' + tabName).show();
$('#' + tabName + '-tab').addClass('active');
if (tabName == 'image-history') {
$scope.listImages();
}
};
$scope.editDescription = function() { $scope.editDescription = function() {
if (!$scope.repo.can_write) { return; } if (!$scope.repo.can_write) { return; }
$('#descriptionEdit')[0].value = $scope.repo.description || ''; $('#descriptionEdit')[0].value = $scope.repo.description || '';
@ -34,6 +50,15 @@ function RepoCtrl($scope, Restangular, $routeParams, $rootScope) {
return Date.parse(dateString); return Date.parse(dateString);
}; };
$scope.listImages = function() {
if ($scope.imageHistory) { return; }
var imageFetch = Restangular.one('repository/' + namespace + '/' + name + '/tag/' + $scope.currentTag.name + '/images');
imageFetch.get().then(function(resp) {
$scope.imageHistory = resp.images;
});
};
var namespace = $routeParams.namespace; var namespace = $routeParams.namespace;
var name = $routeParams.name; var name = $routeParams.name;
var tag = $routeParams.tag || 'latest'; var tag = $routeParams.tag || 'latest';

View file

@ -52,8 +52,8 @@
</ul> </ul>
</span> </span>
</li> </li>
<li class="active"><a href="javascript:void(0)">Current Image</a></li> <li id="current-image-tab" class="active" ng-click="showTab('current-image')"><a href="javascript:void(0)">Current Image</a></li>
<li><a href="javascript:void(0)">Image History</a></li> <li id="image-history-tab" ng-click="showTab('image-history')"><a href="javascript:void(0)">Image History</a></li>
</ul> </ul>
<div id="current-image"> <div id="current-image">
@ -73,6 +73,30 @@
</div> </div>
</div> </div>
<div id="image-history" style="display: none">
<div ng-hide="imageHistory">
Loading images...
</div>
<div ng-show="imageHistory">
<table class="images">
<thead>
<tr>
<td>Created</td>
<td>Comment</td>
<td>ID</td>
</tr>
</thead>
<tr ng-repeat="image in imageHistory">
<td><span am-time-ago="parseDate(image.created)"></span></td>
<td>{{ image.comment }}</td>
<td>{{ image.id }}</td>
</tr>
</table>
</div>
</div>
<!-- Modal edit for the description --> <!-- Modal edit for the description -->
<div class="modal fade" id="editModal"> <div class="modal fade" id="editModal">
<div class="modal-dialog"> <div class="modal-dialog">