mirror of
https://github.com/Joxit/docker-registry-ui.git
synced 2026-02-17 21:19:51 +00:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
102db94ae4 | ||
|
|
7afb100550 | ||
|
|
d1d986448c | ||
|
|
c007eea26d | ||
|
|
dbcd0031d3 | ||
|
|
6180c206b4 | ||
|
|
bc215978ac | ||
|
|
7150fe3245 | ||
|
|
70f860f813 | ||
|
|
30f88520c8 | ||
|
|
c46129f9d0 | ||
|
|
897e6eca0b |
106
README.md
106
README.md
@@ -1,6 +1,7 @@
|
||||
# Docker Registry UI
|
||||
|
||||
## Overview
|
||||
|
||||
This project aims to provide a user interface for your private docker registry v2.
|
||||
There is no default registry on this UI, you should add your own with the UI.
|
||||
You can manage more than one registry server.
|
||||
@@ -12,13 +13,14 @@ This web user interface use [Riot](https://github.com/Riot/riot) the react-like
|
||||
|
||||
## Features
|
||||
|
||||
* List all your repositories/images.
|
||||
* List all tags for a repository/image
|
||||
* Sort the tag list
|
||||
* One interface for many registry
|
||||
* Use a secured docker registry
|
||||
- List all your repositories/images.
|
||||
- List all tags for a repository/image
|
||||
- Sort the tag list
|
||||
- One interface for many registry
|
||||
- Use a secured docker registry
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Basic
|
||||
|
||||
First you need node and npm in order to download dependencies.
|
||||
@@ -30,36 +32,59 @@ npm install
|
||||
```
|
||||
|
||||
Now you can open index.html with your browser or use a http-server
|
||||
|
||||
```sh
|
||||
npm install -g http-server
|
||||
http-server
|
||||
```
|
||||
|
||||
### Docker
|
||||
|
||||
The docker contains the source code and a node webserver in order to serve the docker-registry-ui.
|
||||
|
||||
#### Get the docker image
|
||||
|
||||
You can get the image in three ways
|
||||
|
||||
From sources with this command :
|
||||
|
||||
```sh
|
||||
git clone https://github.com/Joxit/docker-registry-ui.git
|
||||
docker build -t joxit/docker-registry-ui docker-registry-ui
|
||||
docker build -t joxit/docker-registry-ui -f docker-registry-ui/Dockerfile.static docker-registry-ui
|
||||
```
|
||||
|
||||
Or build with the url :
|
||||
```sh
|
||||
|
||||
```sh
|
||||
docker build -t joxit/docker-registry-ui github.com/Joxit/docker-registry-ui
|
||||
docker build -t joxit/docker-registry-ui -f Dockerfile.static github.com/Joxit/docker-registry-ui
|
||||
```
|
||||
|
||||
Or pull the image from [docker hub](https://hub.docker.com/r/joxit/docker-registry-ui/) :
|
||||
|
||||
```sh
|
||||
docker pull joxit/docker-registry-ui
|
||||
docker pull joxit/docker-registry-ui:static
|
||||
```
|
||||
|
||||
#### Run the docker
|
||||
To run the docker and see the website on your 8080 port, try this :
|
||||
|
||||
To run the docker and see the website on your 80 port, try this :
|
||||
|
||||
```sh
|
||||
docker run -d -p 8080:8080 joxit/docker-registry-ui
|
||||
docker run -d -p 80:80 joxit/docker-registry-ui
|
||||
```
|
||||
|
||||
#### Run the static docker
|
||||
|
||||
Some env options are available for use this interface for only one server.
|
||||
|
||||
- `URL`: set the static URL to use. (`Required`)
|
||||
- `DELETE_IMAGES`: if this variable is empty or `false`, delete feature is desactivated. It is activated otherwise.
|
||||
|
||||
```sh
|
||||
docker run -d -p 80:80 -e URL=http://127.0.0.1:5000 -e DELETE_IMAGES=true joxit/docker-registry-ui:static
|
||||
```
|
||||
|
||||
## Using CORS
|
||||
@@ -67,13 +92,66 @@ docker run -d -p 8080:8080 joxit/docker-registry-ui
|
||||
Your server should be configured to accept CORS.
|
||||
|
||||
If your docker registry does not need credentials, you will need to send this HEADER :
|
||||
```
|
||||
Access-Control-Allow-Origin: '*'
|
||||
```
|
||||
|
||||
Access-Control-Allow-Origin: '*'
|
||||
|
||||
If your docker registry need credentials, you will need to send these HEADERS :
|
||||
|
||||
```yml
|
||||
http:
|
||||
headers:
|
||||
Access-Control-Allow-Origin: '<your docker-registry-ui url>'
|
||||
Access-Control-Allow-Credentials: true
|
||||
Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS'] # Optional
|
||||
```
|
||||
Access-Control-Allow-Origin: '<your docker-registry-ui url>'
|
||||
Access-Control-Allow-Credentials: true
|
||||
Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS'] # Optional
|
||||
|
||||
## Using delete
|
||||
|
||||
For deleting images, you need to activate the delete feature in your registry :
|
||||
|
||||
```yml
|
||||
storage:
|
||||
delete:
|
||||
enabled: true
|
||||
```
|
||||
|
||||
And you need to add these HEADERS :
|
||||
|
||||
```yml
|
||||
http:
|
||||
headers:
|
||||
Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE']
|
||||
Access-Control-Expose-Headers: ['Docker-Content-Digest']
|
||||
```
|
||||
|
||||
## Registry example
|
||||
|
||||
Example of docker registry configuration file:
|
||||
|
||||
```yml
|
||||
version: 0.1
|
||||
log:
|
||||
fields:
|
||||
service: registry
|
||||
storage:
|
||||
delete:
|
||||
enabled: true
|
||||
cache:
|
||||
blobdescriptor: inmemory
|
||||
filesystem:
|
||||
rootdirectory: /var/lib/registry
|
||||
http:
|
||||
addr: :5000
|
||||
headers:
|
||||
X-Content-Type-Options: [nosniff]
|
||||
Access-Control-Allow-Origin: ['http://127.0.0.1:8001']
|
||||
Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE']
|
||||
Access-Control-Allow-Headers: ['Authorization']
|
||||
Access-Control-Max-Age: [1728000]
|
||||
Access-Control-Allow-Credentials: [true]
|
||||
Access-Control-Expose-Headers: ['Docker-Content-Digest']
|
||||
auth:
|
||||
htpasswd:
|
||||
realm: basic-realm
|
||||
path: /etc/docker/registry/htpasswd
|
||||
```
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
$@
|
||||
sed -i "s,\${URL},${URL}," scripts/script.js
|
||||
|
||||
if [ -z "${DELETE_IMAGES}" ] || [ "${DELETE_IMAGES}" = false ] ; then
|
||||
sed -i "s/registryUI.isImageRemoveActivated *= *[^,;]*/registryUI.isImageRemoveActivated=false/" scripts/script.js
|
||||
fi
|
||||
|
||||
if [ -z "$@" ]; then
|
||||
nginx -g "daemon off;"
|
||||
else
|
||||
|
||||
47
dist/index.html
vendored
47
dist/index.html
vendored
@@ -13,49 +13,4 @@
|
||||
|
||||
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/>.
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="stylesheet" href="vendor.css">
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:regular,bold,italic,thin,light,bolditalic,black,medium&lang=en" rel="stylesheet" type="text/css">
|
||||
<title>Docker Registry UI</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- Always shows a header, even in smaller screens. -->
|
||||
<div class="mdl-layout mdl-js-layout mdl-layout--fixed-header">
|
||||
<header class="mdl-layout__header">
|
||||
<div class="mdl-layout__header-row">
|
||||
<!-- Title -->
|
||||
<span class="mdl-layout-title">Docker Registry UI</span>
|
||||
<menu></menu>
|
||||
</div>
|
||||
</header>
|
||||
<main class="mdl-layout__content">
|
||||
<div class="page-content">
|
||||
<app></app>
|
||||
</div>
|
||||
</main>
|
||||
<change></change>
|
||||
<add></add>
|
||||
<remove></remove>
|
||||
<footer class="mdl-mini-footer">
|
||||
<div class="mdl-mini-footer__left-section">
|
||||
<div class="mdl-logo">Docker Registry UI</div>
|
||||
<ul class="mdl-mini-footer__link-list">
|
||||
<li><a href="https://github.com/Joxit/docker-registry-ui">Contribute on GitHub</a></li>
|
||||
<li><a href="https://github.com/Joxit/docker-registry-ui/blob/master/LICENSE">Privacy & Terms</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
<script src="scripts/vendor.js"></script>
|
||||
<script src="scripts/tags.js"></script>
|
||||
<script src="scripts/script.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
--><!DOCTYPE html><html><head><meta charset="UTF-8"><link rel="stylesheet" href="vendor.css"><link rel="stylesheet" href="style.css"><link href="https://fonts.googleapis.com/css?family=Roboto:regular,bold,italic,thin,light,bolditalic,black,medium&lang=en" rel="stylesheet" type="text/css"><title>Docker Registry UI</title></head><body><!-- Always shows a header, even in smaller screens. --><div class="mdl-layout mdl-js-layout mdl-layout--fixed-header"><header class="mdl-layout__header"><div class="mdl-layout__header-row"><!-- Title --> <span class="mdl-layout-title">Docker Registry UI</span><menu></menu></div></header><main class="mdl-layout__content"><div class="page-content"><app></app></div></main><change></change><add></add><remove></remove><footer class="mdl-mini-footer"><div class="mdl-mini-footer__left-section"><div class="mdl-logo">Docker Registry UI</div><ul class="mdl-mini-footer__link-list"><li><a href="https://github.com/Joxit/docker-registry-ui">Contribute on GitHub</a></li><li><a href="https://github.com/Joxit/docker-registry-ui/blob/master/LICENSE">Privacy & Terms</a></li></ul></div></footer></div><script src="scripts/vendor.js"></script><script src="scripts/tags.js"></script><script src="scripts/script.js"></script></body></html>
|
||||
2
dist/scripts/script-static.js
vendored
2
dist/scripts/script-static.js
vendored
@@ -15,4 +15,4 @@
|
||||
* 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/>.
|
||||
*/
|
||||
function Http(){this.oReq=new XMLHttpRequest,this._events={}}Http.prototype.addEventListener=function(t,e){this._events[t]=e;var i=this;switch(t){case"loadend":i.oReq.addEventListener("loadend",function(){if(401==this.status){var t=new XMLHttpRequest;for(key in this.http._events)t.addEventListener(key,this.http._events[key]);t.withCredentials=!0,t.open(this.http._method,this.http._url),t.send()}else e.bind(this)()});break;default:i.oReq.addEventListener(t,function(){e.bind(this)()})}},Http.prototype.open=function(t,e){this._method=t,this._url=e,this.oReq.open(t,e)},Http.prototype.send=function(){this.oReq.http=this,this.oReq.send()};var registryUI={};registryUI.url=function(){return"${URL}"},registryUI.catalog={},registryUI.taglist={},riot.mount("catalog"),riot.mount("taglist"),riot.mount("app");
|
||||
function Http(){this.oReq=new XMLHttpRequest,this._events={},this._headers={}}Http.prototype.addEventListener=function(t,e){this._events[t]=e;var s=this;switch(t){case"loadend":s.oReq.addEventListener("loadend",function(){if(401==this.status){var t=new XMLHttpRequest;for(key in this.http._events)t.addEventListener(key,this.http._events[key]);for(key in this.http._headers)t.setRequestHeader(key,this.http._headers[key]);t.withCredentials=!0,t.open(this.http._method,this.http._url),t.send()}else e.bind(this)()});break;default:s.oReq.addEventListener(t,function(){e.bind(this)()})}},Http.prototype.setRequestHeader=function(t,e){this.oReq.setRequestHeader(t,e),this._headers[t]=e},Http.prototype.open=function(t,e){this._method=t,this._url=e,this.oReq.open(t,e)},Http.prototype.send=function(){this.oReq.http=this,this.oReq.send()};var registryUI={};registryUI.url=function(){return"${URL}"},registryUI.isImageRemoveActivated=!0,registryUI.catalog={},registryUI.taglist={},riot.mount("catalog"),riot.mount("taglist"),riot.mount("app");
|
||||
2
dist/scripts/script.js
vendored
2
dist/scripts/script.js
vendored
@@ -15,4 +15,4 @@
|
||||
* 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/>.
|
||||
*/
|
||||
function Http(){this.oReq=new XMLHttpRequest,this._events={}}Http.prototype.addEventListener=function(t,e){this._events[t]=e;var r=this;switch(t){case"loadend":r.oReq.addEventListener("loadend",function(){if(401==this.status){var t=new XMLHttpRequest;for(key in this.http._events)t.addEventListener(key,this.http._events[key]);t.withCredentials=!0,t.open(this.http._method,this.http._url),t.send()}else e.bind(this)()});break;default:r.oReq.addEventListener(t,function(){e.bind(this)()})}},Http.prototype.open=function(t,e){this._method=t,this._url=e,this.oReq.open(t,e)},Http.prototype.send=function(){this.oReq.http=this,this.oReq.send()};var registryUI={};registryUI.url=function(){return registryUI.getRegistryServer(0)},registryUI.getRegistryServer=function(t){try{var e=JSON.parse(localStorage.getItem("registryServer"));if(e instanceof Array)return isNaN(t)?e.map(function(t){return t.trim().replace(/\/*$/,"")}):e[t]}catch(r){}return isNaN(t)?[]:""},registryUI.addServer=function(t){var e=registryUI.getRegistryServer();t=t.trim().replace(/\/*$/,"");var r=e.indexOf(t);r==-1&&(e.push(t),localStorage.setItem("registryServer",JSON.stringify(e)))},registryUI.changeServer=function(t){var e=registryUI.getRegistryServer();t=t.trim().replace(/\/*$/,"");var r=e.indexOf(t);r!=-1&&(e.splice(r,1),e=[t].concat(e),localStorage.setItem("registryServer",JSON.stringify(e)))},registryUI.removeServer=function(t){var e=registryUI.getRegistryServer();t=t.trim().replace(/\/*$/,"");var r=e.indexOf(t);r!=-1&&(e.splice(r,1),localStorage.setItem("registryServer",JSON.stringify(e)))},registryUI.catalog={},registryUI.taglist={},riot.mount("add"),riot.mount("change"),riot.mount("remove"),riot.mount("menu"),riot.mount("app");
|
||||
function Http(){this.oReq=new XMLHttpRequest,this._events={},this._headers={}}Http.prototype.addEventListener=function(e,t){this._events[e]=t;var r=this;switch(e){case"loadend":r.oReq.addEventListener("loadend",function(){if(401==this.status){var e=new XMLHttpRequest;for(key in this.http._events)e.addEventListener(key,this.http._events[key]);for(key in this.http._headers)e.setRequestHeader(key,this.http._headers[key]);e.withCredentials=!0,e.open(this.http._method,this.http._url),e.send()}else t.bind(this)()});break;default:r.oReq.addEventListener(e,function(){t.bind(this)()})}},Http.prototype.setRequestHeader=function(e,t){this.oReq.setRequestHeader(e,t),this._headers[e]=t},Http.prototype.open=function(e,t){this._method=e,this._url=t,this.oReq.open(e,t)},Http.prototype.send=function(){this.oReq.http=this,this.oReq.send()};var registryUI={};registryUI.url=function(){return registryUI.getRegistryServer(0)},registryUI.getRegistryServer=function(e){try{var t=JSON.parse(localStorage.getItem("registryServer"));if(t instanceof Array)return isNaN(e)?t.map(function(e){return e.trim().replace(/\/*$/,"")}):t[e]}catch(r){}return isNaN(e)?[]:""},registryUI.addServer=function(e){var t=registryUI.getRegistryServer();e=e.trim().replace(/\/*$/,"");var r=t.indexOf(e);-1==r&&(t.push(e),localStorage.setItem("registryServer",JSON.stringify(t)))},registryUI.changeServer=function(e){var t=registryUI.getRegistryServer();e=e.trim().replace(/\/*$/,"");var r=t.indexOf(e);-1!=r&&(t.splice(r,1),t=[e].concat(t),localStorage.setItem("registryServer",JSON.stringify(t)))},registryUI.removeServer=function(e){var t=registryUI.getRegistryServer();e=e.trim().replace(/\/*$/,"");var r=t.indexOf(e);-1!=r&&(t.splice(r,1),localStorage.setItem("registryServer",JSON.stringify(t)))},registryUI.isImageRemoveActivated=!0,registryUI.catalog={},registryUI.taglist={},riot.mount("add"),riot.mount("change"),riot.mount("remove"),riot.mount("menu"),riot.mount("app");
|
||||
136
dist/scripts/tags-static.js
vendored
136
dist/scripts/tags-static.js
vendored
File diff suppressed because one or more lines are too long
246
dist/scripts/tags.js
vendored
246
dist/scripts/tags.js
vendored
File diff suppressed because one or more lines are too long
83
dist/scripts/vendor.js
vendored
83
dist/scripts/vendor.js
vendored
File diff suppressed because one or more lines are too long
10
dist/vendor.css
vendored
10
dist/vendor.css
vendored
File diff suppressed because one or more lines are too long
24
gulpfile.js
24
gulpfile.js
@@ -9,19 +9,23 @@ var gulp = require('gulp');
|
||||
var htmlmin = require('gulp-htmlmin');
|
||||
var license = require('gulp-license');
|
||||
var riot = require('gulp-riot');
|
||||
var uglify = require('gulp-uglify');
|
||||
var minifier = require('gulp-uglify/minifier');
|
||||
var uglify = require('uglify-js-harmony');
|
||||
var useref = require('gulp-useref');
|
||||
|
||||
gulp.task('html', function() {
|
||||
var htmlFilter = filter('**/*.html');
|
||||
var assets;
|
||||
return gulp.src(['src/index.html'])
|
||||
.pipe(useref())
|
||||
.pipe(gIf(['*.js'], uglify({
|
||||
preserveComments: 'license'
|
||||
}))) // FIXME
|
||||
.pipe(gIf(['*.js', '!*.min.js'], minifier({}, uglify))) // FIXME
|
||||
.pipe(htmlFilter)
|
||||
.pipe(htmlmin())
|
||||
.pipe(htmlmin({
|
||||
removeComments: false,
|
||||
collapseWhitespace: true,
|
||||
removeRedundantAttributes: true,
|
||||
removeEmptyAttributes: true,
|
||||
minifyJS: uglify
|
||||
}))
|
||||
.pipe(htmlFilter.restore())
|
||||
.pipe(gulp.dest('dist'));
|
||||
});
|
||||
@@ -34,6 +38,7 @@ gulp.task('riot-tag', ['html'], function() {
|
||||
return gulp.src('src/tags/*.tag')
|
||||
.pipe(concat('tags.js'))
|
||||
.pipe(riot())
|
||||
.pipe(minifier({}, uglify))
|
||||
.pipe(license('agpl3', {
|
||||
tiny: false,
|
||||
project: 'docker-registry-ui',
|
||||
@@ -44,9 +49,10 @@ 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'])
|
||||
return gulp.src(['src/tags/catalog.tag', 'src/tags/app.tag', 'src/tags/taglist.tag', 'src/tags/remove-image.tag'])
|
||||
.pipe(concat('tags-static.js'))
|
||||
.pipe(riot())
|
||||
.pipe(minifier({}, uglify))
|
||||
.pipe(license('agpl3', {
|
||||
tiny: false,
|
||||
project: 'docker-registry-ui',
|
||||
@@ -59,7 +65,7 @@ gulp.task('riot-static-tag', ['html'], function() {
|
||||
gulp.task('scripts-static', ['html'], function() {
|
||||
return gulp.src(['src/scripts/http.js', 'src/scripts/static.js'])
|
||||
.pipe(concat('script-static.js'))
|
||||
.pipe(uglify())
|
||||
.pipe(minifier({}, uglify))
|
||||
.pipe(license('agpl3', {
|
||||
tiny: false,
|
||||
project: 'docker-registry-ui',
|
||||
@@ -72,7 +78,7 @@ gulp.task('scripts-static', ['html'], function() {
|
||||
gulp.task('scripts', ['html'], function() {
|
||||
return gulp.src(['src/scripts/http.js', 'src/scripts/script.js'])
|
||||
.pipe(concat('script.js'))
|
||||
.pipe(uglify())
|
||||
.pipe(minifier({}, uglify))
|
||||
.pipe(license('agpl3', {
|
||||
tiny: false,
|
||||
project: 'docker-registry-ui',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "docker-registry-ui",
|
||||
"version": "0.1.0",
|
||||
"version": "0.2.0",
|
||||
"scripts": {
|
||||
"build": "./node_modules/gulp/bin/gulp.js build"
|
||||
},
|
||||
@@ -28,6 +28,7 @@
|
||||
"gulp-useref": "^3.0.0",
|
||||
"material-design-lite": "^1.1",
|
||||
"riot": "^2.3",
|
||||
"riotgear-router": "^1.3.1"
|
||||
"riotgear-router": "^1.3.1",
|
||||
"uglify-js-harmony": "^2.6.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,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/remove-image.tag" type="riot/tag"></script>
|
||||
<script src="tags/add.tag" type="riot/tag"></script>
|
||||
<script src="tags/change.tag" type="riot/tag"></script>
|
||||
<script src="tags/remove.tag" type="riot/tag"></script>
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
function Http() {
|
||||
this.oReq = new XMLHttpRequest();
|
||||
this._events = {};
|
||||
this._headers = {};
|
||||
}
|
||||
|
||||
Http.prototype.addEventListener = function(e, f) {
|
||||
@@ -31,6 +32,9 @@ Http.prototype.addEventListener = function(e, f) {
|
||||
for (key in this.http._events) {
|
||||
req.addEventListener(key, this.http._events[key]);
|
||||
}
|
||||
for (key in this.http._headers) {
|
||||
req.setRequestHeader(key, this.http._headers[key]);
|
||||
}
|
||||
req.withCredentials = true;
|
||||
req.open(this.http._method, this.http._url);
|
||||
req.send();
|
||||
@@ -50,6 +54,11 @@ Http.prototype.addEventListener = function(e, f) {
|
||||
}
|
||||
};
|
||||
|
||||
Http.prototype.setRequestHeader = function(header, value) {
|
||||
this.oReq.setRequestHeader(header, value);
|
||||
this._headers[header] = value;
|
||||
};
|
||||
|
||||
Http.prototype.open = function(m, u) {
|
||||
this._method = m;
|
||||
this._url = u;
|
||||
|
||||
@@ -60,6 +60,7 @@ registryUI.removeServer = function(url) {
|
||||
registryServer.splice(index, 1);
|
||||
localStorage.setItem('registryServer', JSON.stringify(registryServer));
|
||||
}
|
||||
registryUI.isImageRemoveActivated = true;
|
||||
registryUI.catalog = {};
|
||||
registryUI.taglist = {};
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
var registryUI = {}
|
||||
registryUI.url = function() {
|
||||
return '${URL}';
|
||||
}
|
||||
};
|
||||
registryUI.isImageRemoveActivated = true;
|
||||
registryUI.catalog = {};
|
||||
registryUI.taglist = {};
|
||||
|
||||
|
||||
@@ -26,11 +26,13 @@
|
||||
switch (state.name) {
|
||||
case 'taglist':
|
||||
if (registryUI.taglist.display) {
|
||||
registryUI.taglist.loadend = false;
|
||||
registryUI.taglist.display();
|
||||
}
|
||||
break;
|
||||
case 'home':
|
||||
if (registryUI.catalog.display) {
|
||||
registryUI.catalog.loadend = false;
|
||||
registryUI.catalog.display();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<h2 class="mdl-card__title-text">Repositories of { registryUI.url() }</h2>
|
||||
</div>
|
||||
<div id="catalog-spinner" hide="{ registryUI.catalog.loadend }" class="mdl-spinner mdl-js-spinner is-active section-centerd"></div>
|
||||
<ul class="mdl-list">
|
||||
<ul class="mdl-list" show="{ registryUI.catalog.loadend }">
|
||||
<li class="mdl-list__item mdl-menu__item" style="opacity: 1;" each="{ item in registryUI.catalog.repositories }" onclick="registryUI.catalog.go('{item}');">
|
||||
<span class="mdl-list__item-primary-content">
|
||||
<i class="material-icons mdl-list__item-icon">send</i>
|
||||
@@ -57,7 +57,8 @@
|
||||
};
|
||||
oReq.addEventListener('load', function () {
|
||||
if (this.status == 200) {
|
||||
registryUI.catalog.repositories = JSON.parse(this.responseText).repositories.sort();
|
||||
registryUI.catalog.repositories = JSON.parse(this.responseText).repositories || [];
|
||||
registryUI.catalog.repositories.sort();
|
||||
} else if (this.status == 404) {
|
||||
registryUI.catalog.createSnackbar('Server not found');
|
||||
} else {
|
||||
@@ -86,4 +87,4 @@
|
||||
registryUI.catalog.display();
|
||||
</script>
|
||||
<!-- End of tag -->
|
||||
</catalog>
|
||||
</catalog>
|
||||
63
src/tags/remove-image.tag
Normal file
63
src/tags/remove-image.tag
Normal file
@@ -0,0 +1,63 @@
|
||||
<!--
|
||||
Copyright (C) 2016 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/>.
|
||||
-->
|
||||
<remove-image>
|
||||
<a href="#" onclick="registryUI.removeImage.remove('{ opts.name }', '{ opts.tag }')">
|
||||
<i class="material-icons mdl-list__item-icon">delete</i>
|
||||
</a>
|
||||
<script type="text/javascript">
|
||||
registryUI.removeImage = registryUI.removeImage || {}
|
||||
registryUI.removeImage.update = this.update;
|
||||
|
||||
registryUI.removeImage.remove = function (name, tag) {
|
||||
var oReq = new Http();
|
||||
oReq.addEventListener('load', function () {
|
||||
registryUI.taglist.refresh();
|
||||
if (this.status == 200) {
|
||||
if (!this.getAllResponseHeaders().includes('Docker-Content-Digest')) {
|
||||
registryUI.taglist.createSnackbar('You need tu add Access-Control-Expose-Headers: [\'Docker-Content-Digest\'] in your server configuration.');
|
||||
return;
|
||||
}
|
||||
var digest = this.getResponseHeader('Docker-Content-Digest');
|
||||
var oReq = new Http();
|
||||
oReq.addEventListener('load', function () {
|
||||
if (this.status == 200 || this.status == 202) {
|
||||
registryUI.taglist.refresh();
|
||||
registryUI.taglist.createSnackbar('Deleting ' + name + ':' + tag + ' image. Run `registry garbage-collect config.yml` on your registry');
|
||||
} else if (this.status == 404) {
|
||||
registryUI.taglist.createSnackbar('Digest not found');
|
||||
} else {
|
||||
registryUI.taglist.createSnackbar(this.responseText);
|
||||
}
|
||||
});
|
||||
oReq.open('DELETE', registryUI.url() + '/v2/' + name + '/manifests/' + digest);
|
||||
oReq.setRequestHeader('Accept', 'application/vnd.docker.distribution.manifest.v2+json');
|
||||
oReq.addEventListener('error', function () {
|
||||
registryUI.taglist.createSnackbar('An error occurred when deleting image. Check if your server accept DELETE methods Access-Control-Allow-Methods: [\'DELETE\'].');
|
||||
});
|
||||
oReq.send();
|
||||
} else if (this.status == 404) {
|
||||
registryUI.taglist.createSnackbar('Manifest for' + name + ':' + tag + 'not found');
|
||||
} else {
|
||||
registryUI.taglist.createSnackbar(this.responseText);
|
||||
}
|
||||
});
|
||||
oReq.open('HEAD', registryUI.url() + '/v2/' + name + '/manifests/' + tag);
|
||||
oReq.setRequestHeader('Accept', 'application/vnd.docker.distribution.manifest.v2+json');
|
||||
oReq.send();
|
||||
};
|
||||
</script>
|
||||
</remove-image>
|
||||
@@ -24,18 +24,22 @@
|
||||
</a>
|
||||
<h2 class="mdl-card__title-text">Tags of { registryUI.url() + '/' + registryUI.taglist.name }</h2>
|
||||
</div>
|
||||
<div id="taglist-spinner" hide="{ registryUI.taglist.loadend }" class="mdl-spinner mdl-js-spinner section-centerd"></div>
|
||||
<table class="mdl-data-table mdl-js-data-table full-table" style="border: none;">
|
||||
<div id="taglist-spinner" hide="{ registryUI.taglist.loadend }" class="mdl-spinner mdl-js-spinner section-centerd is-active"></div>
|
||||
<table class="mdl-data-table mdl-js-data-table full-table" show="{ registryUI.taglist.loadend }" style="border: none;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="mdl-data-table__cell--non-numeric">Repository</th>
|
||||
<th class="mdl-data-table__header--sorted-ascending" onclick="registryUI.taglist.reverse(this);">Tag</th>
|
||||
<th class="{ registryUI.taglist.asc ? 'mdl-data-table__header--sorted-ascending' : 'mdl-data-table__header--sorted-descending' }" onclick="registryUI.taglist.reverse();">Tag</th>
|
||||
<th show="{ registryUI.isImageRemoveActivated }" ></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr each="{ item in registryUI.taglist.tags }">
|
||||
<td class="mdl-data-table__cell--non-numeric">{ registryUI.taglist.name }</td>
|
||||
<td>{ item }</td>
|
||||
<td show="{ registryUI.isImageRemoveActivated }" >
|
||||
<remove-image name={ registryUI.taglist.name } tag={ item } />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -55,6 +59,7 @@
|
||||
: '');
|
||||
var oReq = new Http();
|
||||
registryUI.taglist.name = name;
|
||||
registryUI.taglist.instance.update();
|
||||
registryUI.taglist.createSnackbar = function (msg) {
|
||||
var snackbar = document.querySelector('#error-snackbar');
|
||||
registryUI.taglist.error = msg;
|
||||
@@ -70,7 +75,8 @@
|
||||
};
|
||||
oReq.addEventListener('load', function () {
|
||||
if (this.status == 200) {
|
||||
registryUI.taglist.tags = JSON.parse(this.responseText).tags.sort();
|
||||
registryUI.taglist.tags = JSON.parse(this.responseText).tags || [];
|
||||
registryUI.taglist.tags.sort();
|
||||
} else if (this.status == 404) {
|
||||
registryUI.taglist.createSnackbar('Server not found');
|
||||
} else {
|
||||
@@ -86,6 +92,7 @@
|
||||
});
|
||||
oReq.open('GET', registryUI.url() + '/v2/' + name + '/tags/list');
|
||||
oReq.send();
|
||||
registryUI.taglist.asc = true;
|
||||
}
|
||||
};
|
||||
registryUI.taglist.display();
|
||||
@@ -94,18 +101,22 @@
|
||||
componentHandler.upgradeElements(this['taglist-tag']);
|
||||
});
|
||||
|
||||
registryUI.taglist.reverse = function (th) {
|
||||
if (th.className == 'mdl-data-table__header--sorted-ascending') {
|
||||
th.className = 'mdl-data-table__header--sorted-descending';
|
||||
registryUI.taglist.reverse = function () {
|
||||
if (registryUI.taglist.asc) {
|
||||
registryUI.taglist.tags.reverse();
|
||||
registryUI.taglist.asc = false;
|
||||
} else {
|
||||
th.className = 'mdl-data-table__header--sorted-ascending';
|
||||
registryUI.taglist.tags.sort();
|
||||
registryUI.taglist.asc = true;
|
||||
}
|
||||
registryUI.taglist.tags.reverse();
|
||||
registryUI.taglist.instance.update();
|
||||
};
|
||||
registryUI.taglist.back = function () {
|
||||
rg.router.go('home');
|
||||
};
|
||||
registryUI.taglist.refresh = function () {
|
||||
rg.router.go(rg.router.current.name, rg.router.current.params);
|
||||
};
|
||||
</script>
|
||||
<!-- End of tag -->
|
||||
</taglist>
|
||||
</taglist>
|
||||
Reference in New Issue
Block a user