mirror of
https://github.com/Joxit/docker-registry-ui.git
synced 2025-04-26 23:19:54 +03:00
[feat #42] Add sha256 for images tag
This commit is contained in:
parent
354d3159bd
commit
3430878e7d
11 changed files with 102 additions and 33 deletions
|
@ -25,6 +25,8 @@ This web user interface uses [Riot](https://github.com/Riot/riot) the react-like
|
|||
- Display image size (see #30)
|
||||
- Add Title when using REGISTRY_URL (see #28)
|
||||
- Alpine and Debian based images with supports for arm32v7
|
||||
- Copy `docker pull` command to clipbloard
|
||||
- Show sha256 for specific tag (hover image tag)
|
||||
|
||||
## Getting Started
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ gulp.task('riot-tag', ['html'], function() {
|
|||
});
|
||||
|
||||
gulp.task('riot-static-tag', ['html'], function() {
|
||||
return gulp.src(['src/tags/catalog.tag', 'src/tags/app.tag', 'src/tags/taglist.tag', 'src/tags/copy-to-clipboard.tag', 'src/tags/remove-image.tag', 'src/tags/image-size.tag'])
|
||||
return gulp.src(['src/tags/catalog.tag', 'src/tags/app.tag', 'src/tags/taglist.tag', 'src/tags/copy-to-clipboard.tag', 'src/tags/remove-image.tag', 'src/tags/image-size.tag', 'src/tags/image-tag.tag'])
|
||||
.pipe(concat('tags-static.js'))
|
||||
.pipe(riot())
|
||||
.pipe(minifier({}, uglify))
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
"devDependencies": {
|
||||
"del": "^3.0.0",
|
||||
"gulp": "^3.9",
|
||||
"gulp-clean-css": "^3.9.3",
|
||||
"gulp-clean-css": "^3.9.4",
|
||||
"gulp-concat": "^2.6.0",
|
||||
"gulp-filter": "^5.1.0",
|
||||
"gulp-htmlmin": "^3.0.0",
|
||||
|
@ -27,7 +27,7 @@
|
|||
"riot": "^3.10.0",
|
||||
"riot-mui": "^0.1.1",
|
||||
"riot-route": "^3.1.3",
|
||||
"uglify-js": "^3.3.16",
|
||||
"uglify-js": "^3.4.0",
|
||||
"uglify-js-harmony": "^2.7.7"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
<!-- build:js scripts/tags.js -->
|
||||
<script src="tags/catalog.tag" type="riot/tag"></script>
|
||||
<script src="tags/taglist.tag" type="riot/tag"></script>
|
||||
<script src="tags/image-tag.tag" type="riot/tag"></script>
|
||||
<script src="tags/remove-image.tag" type="riot/tag"></script>
|
||||
<script src="tags/copy-to-clipboard.tag" type="riot/tag"></script>
|
||||
<script src="tags/add.tag" type="riot/tag"></script>
|
||||
|
|
|
@ -322,6 +322,6 @@ select {
|
|||
padding: 12px 5px;
|
||||
}
|
||||
|
||||
.copy-to-clipboard a {
|
||||
.copy-to-clipboard a:hover {
|
||||
cursor: pointer;
|
||||
}
|
|
@ -93,6 +93,55 @@
|
|||
const args = path.match(re)
|
||||
if (args) return args.slice(1)
|
||||
});
|
||||
|
||||
registryUI.DockerImage = function (name, tag) {
|
||||
this.name = name;
|
||||
this.tag = tag;
|
||||
riot.observable(this);
|
||||
this.on('get-size', function() {
|
||||
if (this.size !== undefined) {
|
||||
return this.trigger('size', this.size);
|
||||
}
|
||||
return this.fillInfo();
|
||||
});
|
||||
this.on('get-sha256', function() {
|
||||
if (this.size !== undefined) {
|
||||
return this.trigger('sha256', this.sha256);
|
||||
}
|
||||
return this.fillInfo();
|
||||
});
|
||||
};
|
||||
|
||||
registryUI.DockerImage.compare = function(e1, e2) {
|
||||
return e1.tag.localeCompare(e2);
|
||||
};
|
||||
|
||||
registryUI.DockerImage.prototype.fillInfo = function() {
|
||||
if (this._fillInfoWaiting) {
|
||||
return;
|
||||
}
|
||||
this._fillInfoWaiting = true;
|
||||
var oReq = new Http();
|
||||
var self = this;
|
||||
oReq.addEventListener('loadend', function () {
|
||||
if (this.status == 200 || this.status == 202) {
|
||||
var response = JSON.parse(this.responseText);
|
||||
self.size = response.layers.reduce(function (acc, e) {
|
||||
return acc + e.size;
|
||||
}, 0);
|
||||
self.sha256 = response.config.digest;
|
||||
self.trigger('size', self.size);
|
||||
self.trigger('sha256', self.sha256);
|
||||
} else if (this.status == 404) {
|
||||
registryUI.errorSnackbar('Manifest for ' + self.name + ':' + self.tag + ' not found');
|
||||
} else {
|
||||
registryUI.snackbar(this.responseText);
|
||||
}
|
||||
});
|
||||
oReq.open('GET', registryUI.url() + '/v2/' + self.name + '/manifests/' + self.tag);
|
||||
oReq.setRequestHeader('Accept', 'application/vnd.docker.distribution.manifest.v2+json');
|
||||
oReq.send();
|
||||
}
|
||||
route.start(true);
|
||||
</script>
|
||||
</app>
|
|
@ -20,7 +20,7 @@
|
|||
<i class="material-icons">content_copy</i>
|
||||
</a>
|
||||
<script type="text/javascript">
|
||||
this.dockerCmd = 'docker pull ' + registryUI.cleanName() + '/' + opts.name + ':' + opts.tag;
|
||||
this.dockerCmd = 'docker pull ' + registryUI.cleanName() + '/' + opts.image.name + ':' + opts.image.tag;
|
||||
this.copy = function () {
|
||||
var copyText = this.refs['input'];
|
||||
copyText.style.display = 'block';
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<image-size>
|
||||
<div>{ this.bytesToSize(this.size) }</div>
|
||||
<div title="Compressed size of your image.">{ this.bytesToSize(this.size) }</div>
|
||||
<script type="text/javascript">
|
||||
var self = this;
|
||||
this.bytesToSize = function (bytes) {
|
||||
|
@ -28,21 +28,10 @@
|
|||
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
|
||||
return Math.ceil(bytes / Math.pow(1024, i)) + ' ' + sizes[i];
|
||||
};
|
||||
var oReq = new Http();
|
||||
oReq.addEventListener('loadend', function () {
|
||||
if (this.status == 200 || this.status == 202) {
|
||||
self.size = JSON.parse(this.responseText).layers.reduce(function (acc, e) {
|
||||
return acc + e.size;
|
||||
}, 0);
|
||||
self.update();
|
||||
} else if (this.status == 404) {
|
||||
registryUI.errorSnackbar('Manifest for ' + opts.name + ':' + opts.tag + ' not found');
|
||||
} else {
|
||||
registryUI.snackbar(this.responseText);
|
||||
}
|
||||
opts.image.on('size', function(size) {
|
||||
self.size = size;
|
||||
self.update();
|
||||
});
|
||||
oReq.open('GET', registryUI.url() + '/v2/' + opts.name + '/manifests/' + opts.tag);
|
||||
oReq.setRequestHeader('Accept', 'application/vnd.docker.distribution.manifest.v2+json');
|
||||
oReq.send();
|
||||
opts.image.trigger('get-size');
|
||||
</script>
|
||||
</image-size>
|
27
src/tags/image-tag.tag
Normal file
27
src/tags/image-tag.tag
Normal file
|
@ -0,0 +1,27 @@
|
|||
<!--
|
||||
Copyright (C) 2016-2018 Jones Magloire @Joxit
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<image-tag>
|
||||
<div title="{ this.sha256 }">{ opts.image.tag }</div>
|
||||
<script type="text/javascript">
|
||||
var self = this;
|
||||
opts.image.on('sha256', function(sha256) {
|
||||
self.sha256 = sha256.substring(0, 19);
|
||||
self.update();
|
||||
});
|
||||
opts.image.trigger('get-sha256');
|
||||
</script>
|
||||
</image-tag>
|
|
@ -15,13 +15,12 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<remove-image>
|
||||
<a href="#" title="Delete image." onclick="registryUI.removeImage.remove('{ opts.name }', '{ opts.tag }')">
|
||||
<a href="#" title="This will delete the image." onclick="registryUI.removeImage.remove('{ opts.image.name }', '{ opts.image.tag }')">
|
||||
<i class="material-icons">delete</i>
|
||||
</a>
|
||||
<script type="text/javascript">
|
||||
registryUI.removeImage = registryUI.removeImage || {}
|
||||
registryUI.removeImage.update = this.update;
|
||||
|
||||
registryUI.removeImage = registryUI.removeImage || {};
|
||||
|
||||
registryUI.removeImage.remove = function (name, tag) {
|
||||
var oReq = new Http();
|
||||
oReq.addEventListener('loadend', function () {
|
||||
|
|
|
@ -37,15 +37,15 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr each="{ item in registryUI.taglist.tags }">
|
||||
<td class="material-card-th-left">{ registryUI.taglist.name }</td>
|
||||
<tr each="{ image in registryUI.taglist.tags }">
|
||||
<td class="material-card-th-left">{ image.name }</td>
|
||||
<td class="copy-to-clipboard">
|
||||
<copy-to-clipboard name={ registryUI.taglist.name } tag={ item }/>
|
||||
<copy-to-clipboard image={ image }/>
|
||||
</td>
|
||||
<td><image-size name={ registryUI.taglist.name } tag={ item } /></td>
|
||||
<td>{ item }</td>
|
||||
<td><image-size image="{ image }" /></td>
|
||||
<td><image-tag image="{ image }" /></td>
|
||||
<td show="{ registryUI.isImageRemoveActivated }">
|
||||
<remove-image name={ registryUI.taglist.name } tag={ item }/>
|
||||
<remove-image image={ image }/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
@ -62,7 +62,9 @@
|
|||
registryUI.taglist.tags = [];
|
||||
if (this.status == 200) {
|
||||
registryUI.taglist.tags = JSON.parse(this.responseText).tags || [];
|
||||
registryUI.taglist.tags.sort();
|
||||
registryUI.taglist.tags = registryUI.taglist.tags.map(function(tag) {
|
||||
return new registryUI.DockerImage(registryUI.taglist.name, tag);
|
||||
}).sort(registryUI.DockerImage.compare);
|
||||
} else if (this.status == 404) {
|
||||
registryUI.snackbar('Server not found', true);
|
||||
} else {
|
||||
|
@ -90,7 +92,7 @@
|
|||
registryUI.taglist.tags.reverse();
|
||||
registryUI.taglist.asc = false;
|
||||
} else {
|
||||
registryUI.taglist.tags.sort();
|
||||
registryUI.taglist.tags.sort(registryUI.DockerImage.compare);
|
||||
registryUI.taglist.asc = true;
|
||||
}
|
||||
registryUI.taglist.instance.update();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue