mirror of
https://github.com/kwk/docker-registry-frontend.git
synced 2024-09-20 07:16:23 +08:00
Add image details support with API v2 (#84)
Revert changes on default projet file Add detailed information for tag listing Removed useless comments, divs, etc -> refactoring Prevent bugs from future changes of API Add digest attribute to Manifest query response Add basic pagination support to tag listing Add environment variable for tags per page Fix bug of image history without config + disabled parent id Fix tags pagination system - Fetch infos for all pages add missing comma Fetch infos for all pages -> simpler fix Disable apache directory listing feature Update tag pagination system to make it feel more like repository pagination system
This commit is contained in:
parent
f287a3811b
commit
d5dd87d1c9
|
@ -136,6 +136,12 @@ By default 20 repositories will be listed per page. To adjust this number, to
|
|||
let's say 50 pass `-e ENV_DEFAULT_REPOSITORIES_PER_PAGE=50` to your `docker run`
|
||||
command.
|
||||
|
||||
# Default tags per page
|
||||
|
||||
By default 10 tags will be listed per page. To adjust this number, to
|
||||
let's say 5 pass `-e ENV_DEFAULT_TAGS_PER_PAGE=5` to your `docker run`
|
||||
command. Note that providing a big number will result in a heavy load on browsers.
|
||||
|
||||
# Contributions are welcome!
|
||||
|
||||
If you like the application, I invite you to contribute and report bugs or feature request on the project's github page: [https://github.com/kwk/docker-registry-frontend][3].
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
# See https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-configure-your-server-to-work-with-html5mode
|
||||
<Directory /var/www/html>
|
||||
Options -Indexes
|
||||
RewriteEngine on
|
||||
|
||||
# Don't rewrite files or directories
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"browseOnly": true, "defaultRepositoriesPerPage": 20}
|
||||
{"browseOnly": true, "defaultRepositoriesPerPage": 20 , "defaultTagsPerPage":10}
|
||||
|
|
|
@ -64,6 +64,10 @@ angular
|
|||
templateUrl: 'repository/repository-detail.html',
|
||||
controller: 'RepositoryDetailController',
|
||||
}).
|
||||
when('/repository/:repositoryUser/:repositoryName/:tagsPerPage?/:tagPage?', {
|
||||
templateUrl: 'repository/repository-detail.html',
|
||||
controller: 'RepositoryDetailController'
|
||||
}).
|
||||
when('/repository/:repositoryUser/:repositoryName/tags/:searchName?', {
|
||||
templateUrl: 'repository/repository-detail.html',
|
||||
controller: 'RepositoryController',
|
||||
|
@ -71,7 +75,7 @@ angular
|
|||
when('/about', {
|
||||
templateUrl: 'about.html',
|
||||
}).
|
||||
when('/tag/:repositoryUser/:repositoryName/:tagName/:imageId', {
|
||||
when('/tag/:repositoryUser/:repositoryName/:tagName/', {
|
||||
templateUrl: 'tag/tag-detail.html',
|
||||
controller: 'TagController',
|
||||
}).
|
||||
|
|
|
@ -8,26 +8,39 @@
|
|||
* Controller of the docker-registry-frontend
|
||||
*/
|
||||
angular.module('image-controller', ['registry-services', 'app-mode-services'])
|
||||
.controller('ImageController', ['$scope', '$route', '$routeParams', '$location', '$log', '$filter', 'Image', 'Ancestry', 'AppMode',
|
||||
function($scope, $route, $routeParams, $location, $log, $filter, Image, Ancestry, AppMode){
|
||||
$scope.imageId = $route.current.params.imageId;
|
||||
$scope.imageDetails = Image.query( {imageId: $scope.imageId} );
|
||||
$scope.imageAncestry = Ancestry.query( {imageId: $scope.imageId} );
|
||||
.controller('ImageController', ['$scope', '$route', '$routeParams', '$location', '$log', '$filter', 'Manifest', 'AppMode',
|
||||
function($scope, $route, $routeParams, $location, $log, $filter, Manifest, AppMode){
|
||||
|
||||
|
||||
$scope.appMode = AppMode.query();
|
||||
$scope.totalImageSize = 0;
|
||||
$scope.imageDetails = Manifest.query({repoUser: $scope.repositoryUser, repoName: $scope.repositoryName, tagName: $scope.tagName});
|
||||
|
||||
|
||||
|
||||
|
||||
// This is not totally working right now (problem with big layers)
|
||||
/**
|
||||
* Calculates the total download size for the image based on
|
||||
* it's ancestry.
|
||||
* it's layers.
|
||||
*/
|
||||
/*
|
||||
$scope.totalImageSize = null;
|
||||
$scope.calculateTotalImageSize = function() {
|
||||
$scope.totalImageSize = 0;
|
||||
angular.forEach($scope.imageAncestry, function (id, key) {
|
||||
/* We have to use the $promise object here to be sure the result is accessible */
|
||||
Image.get( {imageId: id} ).$promise.then(function (result) {
|
||||
if (!isNaN(result.Size-0)) {
|
||||
$scope.totalImageSize += result.Size;
|
||||
var size;
|
||||
angular.forEach($scope.imageDetails.fsLayers, function (id, key) {
|
||||
|
||||
Blob.query({repoUser: $scope.repositoryUser, repoName: $scope.repositoryName, digest: id.blobSum}).$promise.then( function(data, headers){
|
||||
size = data;
|
||||
console.log(data)
|
||||
console.log(size)
|
||||
if(!isNaN(data.contentLength-0)){
|
||||
$scope.totalImageSize += data.contentLength;
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
*/
|
||||
|
||||
}]);
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<tab-heading>
|
||||
General information
|
||||
</tab-heading>
|
||||
<form class="form-horizontal" role="form">
|
||||
<form class="form-horizontal" role="form">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label"><span class="glyphicon glyphicon-user"></span> Author</label>
|
||||
<div class="col-sm-10">
|
||||
|
@ -28,7 +28,7 @@
|
|||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="form-group" >
|
||||
<label class="col-sm-2 control-label"><span class="glyphicon glyphicon-calendar"></span> Created</label>
|
||||
<div class="col-sm-10">
|
||||
<p class="form-control-static">
|
||||
|
@ -52,22 +52,21 @@
|
|||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label"><span class="glyphicon glyphicon-qrcode"></span> ID</label>
|
||||
<div class="col-sm-10">
|
||||
<p class="form-control-static"><a href="image/{{imageDetails.id}}">{{imageDetails.id | limitTo: 12}}</a></p>
|
||||
<p class="form-control-static">
|
||||
{{imageDetails.id | limitTo: 12}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label"><span class="glyphicon glyphicon-arrow-up"></span> Parent's ID</label>
|
||||
<!-- <div class="form-group">
|
||||
<label class="col-sm-2 control-label"><span class="glyphicon glyphicon-arrow-up"></span> Parent's layer ID</label>
|
||||
<div class="col-sm-10">
|
||||
<p class="form-control-static"><a href="image/{{imageDetails.parent}}">{{imageDetails.parent | limitTo: 12}}</a></p>
|
||||
<p class="form-control-static">
|
||||
{{imageDetails.parentLayer | limitTo: 12}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label"><span class="glyphicon glyphicon-compressed"></span> Size <small>(not including base image sizes)</small></label>
|
||||
<div class="col-sm-10">
|
||||
<p class="form-control-static">{{imageDetails.Size/1024/1024 | number: 2}} <b>MB</b> {{imageDetails.Size / 1024 | number: 2}} <b>KB</b> {{imageDetails.Size}} <b>B</b></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
</div> -->
|
||||
|
||||
<!-- <div class="form-group">
|
||||
<label class="col-sm-2 control-label"><span class="glyphicon glyphicon-compressed"></span> Size <small>(including base image sizes)</small></label>
|
||||
<div class="col-sm-10">
|
||||
<p class="form-control-static">
|
||||
|
@ -79,19 +78,27 @@
|
|||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
</form>
|
||||
</tab>
|
||||
<tab>
|
||||
<tab-heading>
|
||||
Image Ancestry
|
||||
Labels
|
||||
</tab-heading>
|
||||
<div class="list-group">
|
||||
<a ng-repeat="img in imageAncestry" href="image/{{img}}" class="list-group-item" ng-class="{active: imageDetails.id==img}">
|
||||
<span class="glyphicon" ng-class="{'glyphicon-arrow-down': ($first&&!$last)||$middle}"></span>
|
||||
{{img | limitTo:12}}
|
||||
</a>
|
||||
</div>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="(key, value) in imageDetails.labels">
|
||||
<td>{{key}}</td>
|
||||
<td>{{value}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</tab>
|
||||
</tabset>
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@
|
|||
<script src="bower_components/moment/moment.js"></script>
|
||||
<script src="bower_components/angular-moment/angular-moment.js"></script>
|
||||
<script src="bower_components/angular-smart-table/dist/smart-table.min.js"></script>
|
||||
<script src="bower_components/angular-filter/dist/angular-filter.js"></script>
|
||||
<script src="bower_components/angular-filter/dist/angular-filter.min.js"></script>
|
||||
<script src="bower_components/angular-bootstrap-checkbox/angular-bootstrap-checkbox.js"></script>
|
||||
<!-- endbower -->
|
||||
<!-- endbuild -->
|
||||
|
|
|
@ -21,7 +21,22 @@ angular.module('repository-detail-controller', ['registry-services', 'app-mode-s
|
|||
$scope.repository = $scope.repositoryUser + '/' + $scope.repositoryName;
|
||||
|
||||
$scope.appMode = AppMode.query();
|
||||
$scope.maxTagsPage = undefined;
|
||||
|
||||
// Method used to disable next & previous links
|
||||
$scope.getNextHref = function (){
|
||||
if($scope.maxTagsPage > $scope.tagsCurrentPage){
|
||||
var nextPageNumber = $scope.tagsCurrentPage + 1;
|
||||
return '/repository/'+$scope.repository+'/'+ $scope.tagsPerPage +'/' +nextPageNumber;
|
||||
}
|
||||
return '#'
|
||||
}
|
||||
$scope.getFirstHref = function (){
|
||||
if($scope.tagsCurrentPage > 1){
|
||||
return '/repository/'+$scope.repository+'/' + $scope.tagsPerPage +'/1';
|
||||
}
|
||||
return '#'
|
||||
}
|
||||
// selected repos
|
||||
$scope.selectedRepositories = [];
|
||||
|
||||
|
|
|
@ -23,3 +23,38 @@
|
|||
</h1>
|
||||
|
||||
<tag-list></tag-list>
|
||||
<nav>
|
||||
<ul class="pager">
|
||||
<li class="previous" ng-class="{disabled: tagsCurrentPage <= 1}">
|
||||
<a href="{{getFirstHref()}}" >
|
||||
<span aria-hidden="true">←</span>
|
||||
First Page
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<div class="btn-group" role="group">
|
||||
<a href="#" class="btn btn-default dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="glyphicon glyphicon-book" aria-hidden="true"> </span> / page:
|
||||
<span ng-show="tagsPerPage">{{tagsPerPage}}</span>
|
||||
<span ng-show="!tagsPerPage">all</span>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="repository/{{repository}}">Show all</a></li>
|
||||
<li role="separator" class="divider"></li>
|
||||
<li><a href="repository/{{repository}}/10/1">10</a></li>
|
||||
<li><a href="repository/{{repository}}/20/1">20</a></li>
|
||||
<li><a href="repository/{{repository}}/40/1">40</a></li>
|
||||
<li><a href="repository/{{repository}}/60/1">60</a></li>
|
||||
<li><a href="repository/{{repository}}/80/1">80</a></li>
|
||||
<li><a href="repository/{{repository}}/100/1">100</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
<li class="next" ng-class="{disabled: maxTagsPage <= tagsCurrentPage || !tagsPerPage}">
|
||||
<a href="{{getNextHref()}}">
|
||||
Next <span aria-hidden="true">→</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
|
|
@ -19,8 +19,9 @@ angular.module('repository-list-controller', ['registry-services', 'app-mode-ser
|
|||
$scope.repositoryName = $route.current.params.repositoryName;
|
||||
$scope.repository = $scope.repositoryUser + '/' + $scope.repositoryName;
|
||||
|
||||
$scope.appMode = AppMode.query();
|
||||
|
||||
$scope.appMode = AppMode.query( function (result){
|
||||
$scope.defaultTagsPerPage = result.defaultTagsPerPage
|
||||
});
|
||||
// How to query the repository
|
||||
$scope.reposPerPage = $route.current.params.reposPerPage;
|
||||
$scope.lastNamespace = $route.current.params.lastNamespace;
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
<!--<input type="checkbox" name="selectedRepos[]" value="{{repo.name}}" ng-model="repo.selected" ng-hide="appMode.browseOnly">-->
|
||||
</td>
|
||||
<td class="grow">
|
||||
<a href="repository/{{repo.name}}"><!--<span class="glyphicon glyphicon-book"></span>--> {{repo.name|trim:username+'/'}}</a>
|
||||
<a href="repository/{{repo.name}}/{{defaultTagsPerPage}}"><!--<span class="glyphicon glyphicon-book"></span>--> {{repo.name|trim:username+'/'}}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -110,7 +110,6 @@ angular.module('registry-services', ['ngResource'])
|
|||
isArray: true,
|
||||
transformResponse: function(data/*, headers*/){
|
||||
var res = [];
|
||||
console.log(data);
|
||||
var resp = angular.fromJson(data);
|
||||
for (var idx in resp.tags){
|
||||
res.push({
|
||||
|
@ -142,13 +141,87 @@ angular.module('registry-services', ['ngResource'])
|
|||
},
|
||||
});
|
||||
}])
|
||||
.factory('Image', ['$resource', function($resource){
|
||||
return $resource('/v1/images/:imageId/json', {}, {
|
||||
'query': { method:'GET', isArray: false},
|
||||
.factory('Manifest', ['$resource', function($resource){
|
||||
|
||||
return $resource('/v2/:repoUser/:repoName/manifests/:tagName', {}, {
|
||||
// Response example:
|
||||
// {
|
||||
// "schemaVersion": 1,
|
||||
// "name": "arthur/busybox",
|
||||
// "tag": "demo",
|
||||
// "architecture": "amd64",
|
||||
// "fsLayers": [
|
||||
// {
|
||||
// "blobSum": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"
|
||||
// },
|
||||
// {
|
||||
// "blobSum": "sha256:d7e8ec85c5abc60edf74bd4b8d68049350127e4102a084f22060f7321eac3586"
|
||||
// }
|
||||
// ],
|
||||
// "history": [
|
||||
// {
|
||||
// "v1Compatibility": "{\"id\":\"3e1018ee907f25aef8c50016296ab33624796511fdbfdbbdeca6a3ed2d0ba4e2\",\"parent\":\"176dfc9032a1ec3ac8586b383e325e1a65d1f5b5e6f46c2a55052b5aea8310f7\",\"created\":\"2016-01-12T17:47:39.251310827Z\",\"container\":\"2732d16efa11ab7da6393645e85a7f2070af94941a782a69e86457a2284f4a69\",\"container_config\":{\"Hostname\":\"ea7fe68f39fd\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) LABEL awesome=Not yet!\"],\"Image\":\"176dfc9032a1ec3ac8586b383e325e1a65d1f5b5e6f46c2a55052b5aea8310f7\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":[],\"Labels\":{\"awesome\":\"Not yet!\",\"test\":\"yes\",\"working\":\"true\"}},\"docker_version\":\"1.9.1\",\"author\":\"Arthur\",\"config\":{\"Hostname\":\"ea7fe68f39fd\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":[\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"],\"Cmd\":[\"sh\"],\"Image\":\"176dfc9032a1ec3ac8586b383e325e1a65d1f5b5e6f46c2a55052b5aea8310f7\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":[],\"Labels\":{\"awesome\":\"Not yet!\",\"test\":\"yes\",\"working\":\"true\"}},\"architecture\":\"amd64\",\"os\":\"linux\"}"
|
||||
// },
|
||||
// {
|
||||
// "v1Compatibility": "{\"id\":\"5c5fb281b01ee091a0fffa5b4a4c7fb7d358e7fb7c49c263d6d7a4e35d199fd0\",\"created\":\"2015-12-08T18:31:50.979824705Z\",\"container\":\"ea7fe68f39fd0df314e841247fb940ddef4c02ab7b5edb0ee724adc3174bc8d9\",\"container_config\":{\"Hostname\":\"ea7fe68f39fd\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) ADD file:c295b0748bf05d4527f500b62ff269bfd0037f7515f1375d2ee474b830bad382 in /\"],\"Image\":\"\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":null,\"Labels\":null},\"docker_version\":\"1.8.3\",\"config\":{\"Hostname\":\"ea7fe68f39fd\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":null,\"Image\":\"\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":null,\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\",\"Size\":1113436}"
|
||||
// }
|
||||
// ],
|
||||
// }
|
||||
'query': {
|
||||
method:'GET',
|
||||
isArray: false,
|
||||
transformResponse: function(data, headers){
|
||||
var res = {};
|
||||
var history = [];
|
||||
var tmp;
|
||||
var resp = angular.fromJson(data);
|
||||
var v1Compatibility = undefined;
|
||||
|
||||
for (var idx in resp.history){
|
||||
|
||||
v1Compatibility = angular.fromJson(resp.history[idx].v1Compatibility);
|
||||
|
||||
if(v1Compatibility !== undefined){
|
||||
tmp = {
|
||||
id : v1Compatibility.id,
|
||||
os : v1Compatibility.os,
|
||||
docker_version: v1Compatibility.docker_version,
|
||||
created: v1Compatibility.created,
|
||||
// parentLayer: v1Compatibility.parent
|
||||
};
|
||||
if(v1Compatibility.author){
|
||||
tmp.author = v1Compatibility.author;
|
||||
}
|
||||
if(v1Compatibility.config && v1Compatibility.config.Labels){
|
||||
tmp.labels = v1Compatibility.config.Labels;
|
||||
}
|
||||
history.push(tmp);
|
||||
}
|
||||
}
|
||||
if(history.length > 0){
|
||||
res = history[0];
|
||||
res.history = history;
|
||||
}
|
||||
res.fsLayers = resp.fsLayers;
|
||||
res.digest = headers('docker-content-digest');
|
||||
res.architecture = resp.architecture;
|
||||
return res;
|
||||
},
|
||||
}
|
||||
});
|
||||
}])
|
||||
.factory('Ancestry', ['$resource', function($resource){
|
||||
return $resource('/v1/images/:imageId/ancestry', {}, {
|
||||
'query': { method:'GET', isArray: true},
|
||||
// This is not totally working right now (problem with big layers)
|
||||
/*
|
||||
.factory('Blob', ['$resource', function($resource){
|
||||
return $resource('/v2/:repoUser/:repoName/blobs/:digest', {}, {
|
||||
|
||||
'query': {
|
||||
method:'HEAD',
|
||||
interceptor: function(data, headers){
|
||||
var res = {contentLength: parseInt(headers('content-length'))};
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}]);
|
||||
}]) */ ;
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
* Controller of the docker-registry-frontend
|
||||
*/
|
||||
angular.module('tag-controller', ['registry-services'])
|
||||
.controller('TagController', ['$scope', '$route', '$routeParams', '$location', '$log', '$filter', 'Tag', 'filterFilter', '$modal',
|
||||
function($scope, $route, $routeParams, $location, $log, $filter, Tag, filterFilter, $modal){
|
||||
.controller('TagController', ['$scope', '$route', '$routeParams', '$location', '$log', '$filter', 'Manifest', 'Tag', 'filterFilter', '$modal',
|
||||
function($scope, $route, $routeParams, $location, $log, $filter, Manifest, Tag, filterFilter, $modal){
|
||||
|
||||
$scope.$route = $route;
|
||||
$scope.$location = $location;
|
||||
|
@ -20,16 +20,50 @@ angular.module('tag-controller', ['registry-services'])
|
|||
$scope.repositoryName = $route.current.params.repositoryName;
|
||||
$scope.repository = $scope.repositoryUser + '/' + $scope.repositoryName;
|
||||
$scope.tagName = $route.current.params.tagName;
|
||||
$scope.tagsPerPage = $route.current.params.tagsPerPage;
|
||||
|
||||
// How to query the tags
|
||||
// Fetch tags
|
||||
$scope.tags = Tag.query({
|
||||
repoUser: $scope.repositoryUser,
|
||||
repoName: $scope.repositoryName
|
||||
}, function(result){
|
||||
// Determine the number of pages
|
||||
$scope.maxTagsPage = parseInt(Math.ceil(parseFloat(result.length)/parseFloat($scope.tagsPerPage)));
|
||||
// Compute the right current page number
|
||||
$scope.tagsCurrentPage = $route.current.params.tagPage;
|
||||
if(! $scope.tagsCurrentPage){
|
||||
$scope.tagsCurrentPage = 1;
|
||||
}else{
|
||||
$scope.tagsCurrentPage = parseInt($scope.tagsCurrentPage)
|
||||
if($scope.tagsCurrentPage > $scope.maxTagsPage || $scope.tagsCurrentPage < 1){
|
||||
$scope.tagsCurrentPage = 1;
|
||||
}
|
||||
}
|
||||
// Select wanted tags
|
||||
var idxShift = 0;
|
||||
$scope.displayedTags = $scope.tags;
|
||||
if($scope.tagsPerPage){
|
||||
idxShift = ($scope.tagsCurrentPage - 1) * $scope.tagsPerPage;
|
||||
$scope.displayedTags = $scope.displayedTags.slice(idxShift, ($scope.tagsCurrentPage ) * $scope.tagsPerPage );
|
||||
}
|
||||
var tmpIdx;
|
||||
// Fetch wanted manifests
|
||||
for (var idx in $scope.displayedTags){
|
||||
if(!isNaN(idx)){
|
||||
tmpIdx = parseInt(idx) + idxShift;
|
||||
if ( result[tmpIdx].hasOwnProperty('name') ) {
|
||||
result[tmpIdx].details = Manifest.query({repoUser: $scope.repositoryUser, repoName: $scope.repositoryName, tagName: result[tmpIdx].name});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
// Copy collection for rendering in a smart-table
|
||||
$scope.displayedTags = [].concat($scope.tags);
|
||||
|
||||
|
||||
// selected tags
|
||||
$scope.selection = [];
|
||||
|
||||
|
@ -38,13 +72,6 @@ angular.module('tag-controller', ['registry-services'])
|
|||
return filterFilter($scope.displayedTags, { selected: true });
|
||||
};
|
||||
|
||||
// watch fruits for changes
|
||||
$scope.$watch('tags|filter:{selected:true}', function(nv) {
|
||||
$scope.selection = nv.map(function (tag) {
|
||||
return $scope.repository + ':' + tag.name;
|
||||
});
|
||||
}, true);
|
||||
|
||||
$scope.openConfirmTagDeletionDialog = function(size) {
|
||||
var modalInstance = $modal.open({
|
||||
animation: true,
|
||||
|
@ -67,4 +94,4 @@ angular.module('tag-controller', ['registry-services'])
|
|||
});
|
||||
};
|
||||
|
||||
}]);
|
||||
}]);
|
|
@ -7,21 +7,42 @@
|
|||
</button>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="" ng-class="{strike: deleted}"><span class="glyphicon glyphicon-tag"></span> Tag</th>
|
||||
<th ng-class="{strike: deleted}"><span class="glyphicon glyphicon-tag"></span> Tag</th>
|
||||
<th ><span class="glyphicon glyphicon-qrcode"></span> Image ID</th>
|
||||
<th ><span class="glyphicon glyphicon-calendar"></span> Created</th>
|
||||
<th ><span class="glyphicon glyphicon-user"></span> Author</th>
|
||||
<th ><span class="glyphicon glyphicon-eye-open"></span> Docker version</th>
|
||||
<!-- <th ><span class="glyphicon glyphicon-arrow-up"></span> Parent's ID</th> -->
|
||||
<!-- <th><span class="glyphicon glyphicon-compressed"></span> Size (MB)</th> -->
|
||||
</tr>
|
||||
<tr>
|
||||
<th><input class="input-sm form-control" placeholder="Filter tags on this page" type="search" ng-model="search.name"/></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="tag in tags | filter:search ">
|
||||
<tr ng-repeat="tag in displayedTags | filter:search ">
|
||||
<td>
|
||||
<span ng-bind-html="tag.name"></span>
|
||||
<a ng-bind-html="tag.name" href="tag/{{repositoryUser}}/{{repositoryName}}/{{tag.name}}">{{tag.name}}</a>
|
||||
</td>
|
||||
<td><span ng-bind-html="tag.details.id | limitTo: 12"></span></td>
|
||||
<td am-time-ago="tag.details.created"></td>
|
||||
<td><span ng-bind-html="tag.details.author | linky"></span></td>
|
||||
<td ng-bind-html="tag.details.docker_version"></td>
|
||||
<!-- <td><span ng-bind-html="tag.details.parent | limitTo: 12"></span></td> -->
|
||||
<!-- <td>
|
||||
<button type="submit" class="btn btn-info btn-xs" ng-click="calculateTotalImageSize()" ng-show="totalImageSize===null" title="Calculate total image size">
|
||||
<span class="glyphicon glyphicon-stats"></span>
|
||||
</button>
|
||||
<span ng-show="totalImageSize===null" ng-bind-html="tag.details.Size / 1024 / 1024 | number: 2"></span>
|
||||
<span ng-show="totalImageSize!==null">
|
||||
{{totalImageSize / 1024 / 1024 | number: 2}}
|
||||
</span>
|
||||
</td> -->
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -40,7 +40,8 @@ echo "{\"host\": \"$ENV_REGISTRY_PROXY_FQDN\", \"port\": $ENV_REGISTRY_PROXY_POR
|
|||
# Overwrite browse-only option for now since only browse-only is working right now
|
||||
ENV_MODE_BROWSE_ONLY=true
|
||||
[[ -z "$ENV_DEFAULT_REPOSITORIES_PER_PAGE" ]] && ENV_DEFAULT_REPOSITORIES_PER_PAGE=20
|
||||
echo "{\"browseOnly\":$ENV_MODE_BROWSE_ONLY, \"defaultRepositoriesPerPage\":$ENV_DEFAULT_REPOSITORIES_PER_PAGE}" > /var/www/html/app-mode.json
|
||||
[[ -z "$ENV_DEFAULT_TAGS_PER_PAGE" ]] && ENV_DEFAULT_TAGS_PER_PAGE=10
|
||||
echo "{\"browseOnly\":$ENV_MODE_BROWSE_ONLY, \"defaultRepositoriesPerPage\":$ENV_DEFAULT_REPOSITORIES_PER_PAGE , \"defaultTagsPerPage\":$ENV_DEFAULT_TAGS_PER_PAGE }" > /var/www/html/app-mode.json
|
||||
if [ "$ENV_MODE_BROWSE_ONLY" == "true" ]; then
|
||||
echo "export APACHE_ARGUMENTS='-D FRONTEND_BROWSE_ONLY_MODE'" >> /etc/apache2/envvars
|
||||
fi
|
||||
|
|
Loading…
Reference in a new issue